1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4#include <stdint.h> 5#include <string.h> 6#include <threads.h> 7#include <unistd.h> 8 9#include <ddk/binding.h> 10#include <ddk/debug.h> 11#include <ddk/device.h> 12#include <ddk/protocol/i2c-impl.h> 13#include <ddk/protocol/platform-bus.h> 14#include <ddk/protocol/platform-defs.h> 15#include <ddk/protocol/platform-device.h> 16 17#include <fbl/alloc_checker.h> 18#include <fbl/auto_call.h> 19#include <fbl/string_printf.h> 20 21#include <lib/zx/time.h> 22 23#include <zircon/assert.h> 24#include <zircon/types.h> 25 26#include "imx-i2c-regs.h" 27#include "imx-i2c.h" 28 29namespace imx_i2c { 30 31constexpr size_t kMaxTransferSize = UINT16_MAX - 1; // More than enough 32 33uint32_t ImxI2cDevice::I2cImplGetBusCount() { 34 return dev_cnt_; 35} 36 37zx_status_t ImxI2cDevice::I2cImplGetMaxTransferSize(uint32_t bus_id, size_t* out_size) { 38 *out_size = kMaxTransferSize; 39 return ZX_OK; 40} 41 42zx_status_t ImxI2cDevice::I2cImplSetBitRate(uint32_t bus_id, uint32_t bitrate) { 43 // TODO(andresoportus): Support changing frequencies 44 return ZX_ERR_NOT_SUPPORTED; 45} 46 47zx_status_t ImxI2cDevice::I2cImplTransact(uint32_t bus_id, i2c_impl_op_t* ops, size_t count) { 48 if (!atomic_load(&ready_)) { 49 return ZX_ERR_SHOULD_WAIT; 50 } 51 zx_status_t status = ZX_OK; 52 for (size_t i = 0; i < count; ++i) { 53 if (ops[i].address > 0xFF) { 54 return ZX_ERR_NOT_SUPPORTED; 55 } 56 if (ops[i].is_read) { 57 status = Read(static_cast<uint8_t>(ops[i].address), ops[i].buf, ops[i].length, 58 ops[i].stop); 59 } else { 60 status = Write(static_cast<uint8_t>(ops[i].address), ops[i].buf, ops[i].length, 61 ops[i].stop); 62 } 63 if (status != ZX_OK) { 64 Reset(); 65 return status; 66 } 67 } 68 return ZX_OK; 69} 70 71zx_status_t ImxI2cDevice::WaitFor(Wait type) { 72 zx::time timeout = zx::deadline_after(zx::msec(10)); 73 while (zx::clock::get_monotonic() < timeout) { 74 switch (type) { 75 case Wait::kIdle: 76 if (!StatusReg::Get().ReadFrom(mmio_.get()).bus_busy()) { 77 return ZX_OK; 78 } 79 break; 80 case Wait::kBusy: 81 if (StatusReg::Get().ReadFrom(mmio_.get()).bus_busy()) { 82 return ZX_OK; 83 } 84 break; 85 case Wait::kInterruptPending: 86 if (StatusReg::Get().ReadFrom(mmio_.get()).interrupt_pending()) { 87 return ZX_OK; 88 } 89 break; 90 } 91 // TODO(andresoportus): Use interrupts instead of polling 92 zx::nanosleep(zx::deadline_after(zx::usec(10))); 93 } 94 zxlogf(ERROR, "ImxI2cDevice::WaitFor: %s timedout\n", WaitStr(type)); 95 ControlReg::Get().ReadFrom(mmio_.get()).Print(); 96 StatusReg::Get().ReadFrom(mmio_.get()).Print(); 97 return ZX_ERR_TIMED_OUT; 98} 99 100zx_status_t ImxI2cDevice::Start() { 101 ControlReg::Get().ReadFrom(mmio_.get()).set_master(1).set_transmit(1).WriteTo(mmio_.get()); 102 return WaitFor(Wait::kBusy); 103} 104 105void ImxI2cDevice::Stop() { 106 ControlReg::Get().ReadFrom(mmio_.get()).set_master(0).set_transmit(0).WriteTo(mmio_.get()); 107} 108 109void ImxI2cDevice::Reset() { 110 zxlogf(INFO, "ImxI2cDevice::Reset: reseting...\n"); 111 ControlReg::Get().FromValue(0).WriteTo(mmio_.get()); // Implies set_enable(0). 112 StatusReg::Get().FromValue(0).WriteTo(mmio_.get()); 113 ControlReg::Get().FromValue(0).set_enable(1).WriteTo(mmio_.get()); 114 WaitFor(Wait::kIdle); // No check for error from it 115} 116 117zx_status_t ImxI2cDevice::RxData(uint8_t* buf, size_t length, bool stop) { 118 zx_status_t status; 119 if (length == 0) { 120 return ZX_OK; 121 } 122 123 // Switch to Rx mode 124 auto control = ControlReg::Get().ReadFrom(mmio_.get()).set_transmit(0).set_tx_ack_disable(0); 125 if (length == 1) { 126 // If length is 1 then we need to no ACK (to finish RX) immediately 127 control.set_tx_ack_disable(1); 128 } 129 control.WriteTo(mmio_.get()); 130 131 StatusReg::Get().ReadFrom(mmio_.get()).set_interrupt_pending(0).WriteTo(mmio_.get()); 132 // Required dummy read, per reference manual: 133 // "If Master Receive mode is required, then I2C_I2CR[MTX] should be toggled and a dummy read 134 // of the I2C_I2DR register must be executed to trigger receive data." 135 DataReg::Get().ReadFrom(mmio_.get()).data(); 136 137 for (size_t i = 0; i < length; ++i) { 138 139 // Wait for and check Rx transfer completed 140 status = WaitFor(Wait::kInterruptPending); 141 if (status != ZX_OK) { 142 return status; 143 } 144 if (!StatusReg::Get().ReadFrom(mmio_.get()).transfer_complete()) { 145 return ZX_ERR_IO; 146 } 147 StatusReg::Get().ReadFrom(mmio_.get()).set_interrupt_pending(0).WriteTo(mmio_.get()); 148 if (i == length - 2) { 149 // Set TX_ACK_DISABLE two bytes before last 150 ControlReg::Get().ReadFrom(mmio_.get()).set_tx_ack_disable(1).WriteTo(mmio_.get()); 151 } 152 if (i == length - 1) { 153 if (stop) { 154 Stop(); // Set STOP one byte before the last 155 } 156 } 157 buf[i] = DataReg::Get().ReadFrom(mmio_.get()).data(); 158 } 159 return ZX_OK; 160} 161 162zx_status_t ImxI2cDevice::TxData(const uint8_t* buf, size_t length, bool stop) { 163 for (size_t i = 0; i < length; ++i) { 164 if (i == length - 1 && stop) { 165 Stop(); // Set STOP one byte before the last 166 } 167 StatusReg::Get().ReadFrom(mmio_.get()).set_interrupt_pending(0).WriteTo(mmio_.get()); 168 DataReg::Get().FromValue(0).set_data(buf[i]).WriteTo(mmio_.get()); 169 170 // Wait for and check Tx transfer completed 171 zx_status_t status = WaitFor(Wait::kInterruptPending); 172 if (status != ZX_OK) { 173 return status; 174 } 175 if (!StatusReg::Get().ReadFrom(mmio_.get()).transfer_complete()) { 176 return ZX_ERR_IO; 177 } 178 } 179 return ZX_OK; 180} 181 182zx_status_t ImxI2cDevice::TxAddress(uint8_t addr, bool is_read) { 183 uint8_t data = static_cast<uint8_t>((addr << 1) | static_cast<uint8_t>(is_read)); 184 return TxData(&data, 1, false); 185} 186 187zx_status_t ImxI2cDevice::Read(uint8_t addr, void* buf, size_t len, bool stop) { 188 ControlReg::Get().ReadFrom(mmio_.get()).set_repeat_start(1).WriteTo(mmio_.get()); 189 zx_status_t status = TxAddress(addr, true); 190 if (status != ZX_OK) { 191 return status; 192 } 193 return RxData(static_cast<uint8_t*>(buf), len, stop); 194} 195 196zx_status_t ImxI2cDevice::Write(uint8_t addr, const void* buf, size_t len, bool stop) { 197 zx_status_t status = Start(); 198 if (status != ZX_OK) { 199 return status; 200 } 201 status = TxAddress(addr, false); 202 if (status != ZX_OK) { 203 return status; 204 } 205 return TxData(static_cast<const uint8_t*>(buf), len, stop); 206} 207 208void ImxI2cDevice::DdkUnbind() { 209 ShutDown(); 210 DdkRemove(); 211} 212 213void ImxI2cDevice::DdkRelease() { 214 delete this; 215} 216 217int ImxI2cDevice::Thread() { 218 Reset(); 219 ready_.store(true); 220//#define TEST_USB_REGS_READ 221#ifdef TEST_USB_REGS_READ 222 for (int i = 0; i < 0xC; i += 2) { 223 uint8_t data_write = static_cast<uint8_t>(i); 224 uint8_t data_read[2]; 225 i2c_impl_op_t ops[] = { 226 {.address = 0x50, .buf = &data_write, .length = 1, .is_read = false, .stop = false}, 227 {.address = 0x50, .buf = data_read, .length = 2, .is_read = true, .stop = true}, 228 }; 229 I2cImplTransact(0, ops, 2); 230 zxlogf(INFO, "USB-C Reg:0x%02X Value:0x%02X%02X\n", i, data_read[1], data_read[0]); 231 } 232#endif 233 return 0; 234} 235 236void ImxI2cDevice::ShutDown() { 237 thrd_join(thread_, NULL); 238 io_buffer_release(®s_iobuff_); 239} 240 241zx_status_t ImxI2cDevice::Bind(int id) { 242 zx_status_t status; 243 244 platform_device_protocol_t pdev; 245 if (device_get_protocol(parent(), ZX_PROTOCOL_PLATFORM_DEV, &pdev) != ZX_OK) { 246 zxlogf(ERROR, "imx_i2c_bind: ZX_PROTOCOL_PLATFORM_DEV not available\n"); 247 return ZX_ERR_NOT_SUPPORTED; 248 } 249 platform_bus_protocol_t pbus; 250 if (device_get_protocol(parent(), ZX_PROTOCOL_PLATFORM_BUS, &pbus) != ZX_OK) { 251 zxlogf(ERROR, "imx_i2c_bind: ZX_PROTOCOL_PLATFORM_BUS not available\n"); 252 return ZX_ERR_NOT_SUPPORTED; 253 } 254 i2c_impl_protocol_t i2c_proto = { 255 .ops = &ops_, 256 .ctx = this, 257 }; 258 pbus_register_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c_proto, NULL, NULL); 259 260 status = pdev_map_mmio_buffer(&pdev, id, ZX_CACHE_POLICY_UNCACHED_DEVICE, ®s_iobuff_); 261 if (status != ZX_OK) { 262 zxlogf(ERROR, "ImxI2cDevice::Bind: pdev_map_mmio_buffer failed: %d\n", status); 263 return status; 264 } 265 266 fbl::AllocChecker ac; 267 mmio_ = fbl::make_unique_checked<hwreg::RegisterIo>(&ac, io_buffer_virt(®s_iobuff_)); 268 if (!ac.check()) { 269 zxlogf(ERROR, "ImxI2cDevice::Bind: no memory for RegisterIo\n"); 270 io_buffer_release(®s_iobuff_); 271 return ZX_ERR_NO_MEMORY; 272 } 273 274 int rc = thrd_create_with_name(&thread_, 275 [](void* arg) -> int { 276 return reinterpret_cast<ImxI2cDevice*>(arg)->Thread(); 277 }, 278 this, 279 "imxi2c-thread"); 280 if (rc != thrd_success) { 281 io_buffer_release(®s_iobuff_); 282 return ZX_ERR_INTERNAL; 283 } 284 285 auto cleanup = fbl::MakeAutoCall([&]() { ShutDown(); }); 286 auto name = fbl::StringPrintf("imx-i2c-%d", id); 287 status = DdkAdd(name.c_str()); 288 if (status != ZX_OK) { 289 zxlogf(ERROR, "ImxI2cDevice::Bind: DdkAdd failed: %d\n", status); 290 return status; 291 } 292 cleanup.cancel(); 293 return ZX_OK; 294} 295 296} // namespace imx_i2c 297 298extern "C" zx_status_t imx_i2c_bind(void* ctx, zx_device_t* parent) { 299 platform_device_protocol_t pdev; 300 if (device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_DEV, &pdev) != ZX_OK) { 301 zxlogf(ERROR, "imx_i2c_bind: ZX_PROTOCOL_PLATFORM_DEV not available\n"); 302 return ZX_ERR_NOT_SUPPORTED; 303 } 304 305 pdev_device_info_t info; 306 zx_status_t status = pdev_get_device_info(&pdev, &info); 307 if (status != ZX_OK) { 308 zxlogf(ERROR, "imx_i2c_bind: pdev_get_device_info failed\n"); 309 return ZX_ERR_NOT_SUPPORTED; 310 } 311 312 fbl::AllocChecker ac; 313 for (uint32_t i = 0; i < info.mmio_count; i++) { 314 auto dev = fbl::make_unique_checked<imx_i2c::ImxI2cDevice>(&ac, parent, info.mmio_count); 315 if (!ac.check()) { 316 zxlogf(ERROR, "imx_i2c_bind: ZX_ERR_NO_MEMORY\n"); 317 return ZX_ERR_NO_MEMORY; 318 } 319 status = dev->Bind(i); 320 if (status == ZX_OK) { 321 // devmgr is now in charge of the memory for dev 322 __UNUSED auto ptr = dev.release(); 323 } 324 } 325 return status; 326} 327