1// Copyright 2017 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 5#include <ddk/binding.h> 6#include <ddk/debug.h> 7#include <ddk/device.h> 8#include <ddk/mmio-buffer.h> 9#include <ddk/protocol/i2c-impl.h> 10#include <ddk/protocol/platform-defs.h> 11#include <ddk/protocol/platform-bus.h> 12#include <ddk/protocol/platform-device.h> 13#include <hw/reg.h> 14#include <lib/sync/completion.h> 15#include <zircon/process.h> 16#include <zircon/assert.h> 17 18#include <stdlib.h> 19#include <stdio.h> 20#include <string.h> 21#include <unistd.h> 22#include <threads.h> 23 24#include "dw-i2c-regs.h" 25 26typedef struct { 27 zx_handle_t irq_handle; 28 zx_handle_t event_handle; 29 mmio_buffer_t regs_iobuff; 30 zx_duration_t timeout; 31 32 uint32_t tx_fifo_depth; 33 uint32_t rx_fifo_depth; 34} i2c_dw_dev_t; 35 36typedef struct { 37 platform_device_protocol_t pdev; 38 i2c_impl_protocol_t i2c; 39 zx_device_t* zxdev; 40 i2c_dw_dev_t* i2c_devs; 41 size_t i2c_dev_count; 42} i2c_dw_t; 43 44static zx_status_t i2c_dw_read(i2c_dw_dev_t* dev, uint8_t *buff, uint32_t len, bool stop); 45static zx_status_t i2c_dw_write(i2c_dw_dev_t* dev, const uint8_t *buff, uint32_t len, bool stop); 46static zx_status_t i2c_dw_set_slave_addr(i2c_dw_dev_t* dev, uint16_t addr); 47 48zx_status_t i2c_dw_dumpstate(i2c_dw_dev_t* dev) { 49 zxlogf(INFO, "########################\n"); 50 zxlogf(INFO, "%s\n", __FUNCTION__); 51 zxlogf(INFO, "########################\n"); 52 zxlogf(INFO, "DW_I2C_ENABLE_STATUS = \t0x%x\n", I2C_DW_READ32(DW_I2C_ENABLE_STATUS)); 53 zxlogf(INFO, "DW_I2C_ENABLE = \t0x%x\n", I2C_DW_READ32(DW_I2C_ENABLE)); 54 zxlogf(INFO, "DW_I2C_CON = \t0x%x\n", I2C_DW_READ32(DW_I2C_CON)); 55 zxlogf(INFO, "DW_I2C_TAR = \t0x%x\n", I2C_DW_READ32(DW_I2C_TAR)); 56 zxlogf(INFO, "DW_I2C_HS_MADDR = \t0x%x\n", I2C_DW_READ32(DW_I2C_HS_MADDR)); 57 zxlogf(INFO, "DW_I2C_SS_SCL_HCNT = \t0x%x\n", I2C_DW_READ32(DW_I2C_SS_SCL_HCNT)); 58 zxlogf(INFO, "DW_I2C_SS_SCL_LCNT = \t0x%x\n", I2C_DW_READ32(DW_I2C_SS_SCL_LCNT)); 59 zxlogf(INFO, "DW_I2C_FS_SCL_HCNT = \t0x%x\n", I2C_DW_READ32(DW_I2C_FS_SCL_HCNT)); 60 zxlogf(INFO, "DW_I2C_FS_SCL_LCNT = \t0x%x\n", I2C_DW_READ32(DW_I2C_FS_SCL_LCNT)); 61 zxlogf(INFO, "DW_I2C_INTR_MASK = \t0x%x\n", I2C_DW_READ32(DW_I2C_INTR_MASK)); 62 zxlogf(INFO, "DW_I2C_RAW_INTR_STAT = \t0x%x\n", I2C_DW_READ32(DW_I2C_RAW_INTR_STAT)); 63 zxlogf(INFO, "DW_I2C_RX_TL = \t0x%x\n", I2C_DW_READ32(DW_I2C_RX_TL)); 64 zxlogf(INFO, "DW_I2C_TX_TL = \t0x%x\n", I2C_DW_READ32(DW_I2C_TX_TL)); 65 zxlogf(INFO, "DW_I2C_STATUS = \t0x%x\n", I2C_DW_READ32(DW_I2C_STATUS)); 66 zxlogf(INFO, "DW_I2C_TXFLR = \t0x%x\n", I2C_DW_READ32(DW_I2C_TXFLR)); 67 zxlogf(INFO, "DW_I2C_RXFLR = \t0x%x\n", I2C_DW_READ32(DW_I2C_RXFLR)); 68 zxlogf(INFO, "DW_I2C_COMP_PARAM_1 = \t0x%x\n", I2C_DW_READ32(DW_I2C_COMP_PARAM_1)); 69 zxlogf(INFO, "DW_I2C_TX_ABRT_SOURCE = \t0x%x\n", I2C_DW_READ32(DW_I2C_TX_ABRT_SOURCE)); 70 return ZX_OK; 71} 72 73static zx_status_t i2c_dw_enable_wait(i2c_dw_dev_t* dev, bool enable) { 74 int max_poll = 100; 75 int poll = 0; 76 77 // set enable bit to 0 78 I2C_DW_SET_BITS32(DW_I2C_ENABLE, DW_I2C_ENABLE_ENABLE_START, DW_I2C_ENABLE_ENABLE_BITS, enable); 79 80 do { 81 if (I2C_DW_GET_BITS32(DW_I2C_ENABLE_STATUS, DW_I2C_ENABLE_STATUS_EN_START, 82 DW_I2C_ENABLE_STATUS_EN_BITS) == enable) { 83 // we are done. exit 84 return ZX_OK; 85 } 86 // sleep 10 times the signaling period for the highest i2c transfer speed (400K) ~25uS 87 usleep(25); 88 } while (poll++ < max_poll); 89 90 zxlogf(ERROR, "%s: Could not %s I2C contoller! DW_I2C_ENABLE_STATUS = 0x%x\n", 91 __FUNCTION__, 92 enable? "enable" : "disable", 93 I2C_DW_READ32(DW_I2C_ENABLE_STATUS)); 94 i2c_dw_dumpstate(dev); 95 96 return ZX_ERR_TIMED_OUT; 97} 98 99static zx_status_t i2c_dw_enable(i2c_dw_dev_t* dev) { 100 return i2c_dw_enable_wait(dev, I2C_ENABLE); 101 return ZX_OK; 102} 103 104static void i2c_dw_clear_intrrupts(i2c_dw_dev_t* dev) { 105 I2C_DW_READ32(DW_I2C_CLR_INTR); // reading this register will clear all the interrupts 106} 107 108static void i2c_dw_disable_interrupts(i2c_dw_dev_t* dev) { 109 I2C_DW_WRITE32(DW_I2C_INTR_MASK, 0); 110} 111 112static void i2c_dw_enable_interrupts(i2c_dw_dev_t* dev, uint32_t flag) { 113 I2C_DW_WRITE32(DW_I2C_INTR_MASK, flag); 114} 115 116static zx_status_t i2c_dw_disable(i2c_dw_dev_t* dev) { 117 return i2c_dw_enable_wait(dev, I2C_DISABLE); 118} 119 120static zx_status_t i2c_dw_wait_event(i2c_dw_dev_t* dev, uint32_t sig_mask) { 121 uint32_t observed; 122 zx_time_t deadline = zx_deadline_after(dev->timeout); 123 124 sig_mask |= I2C_ERROR_SIGNAL; 125 126 zx_status_t status = zx_object_wait_one(dev->event_handle, sig_mask, deadline, &observed); 127 128 if (status != ZX_OK) { 129 return status; 130 } 131 132 zx_object_signal(dev->event_handle, observed, 0); 133 134 if (observed & I2C_ERROR_SIGNAL) { 135 return ZX_ERR_TIMED_OUT; 136 } 137 138 return ZX_OK; 139} 140 141// Thread to handle interrupts 142static int i2c_dw_irq_thread(void* arg) { 143 i2c_dw_dev_t* dev = (i2c_dw_dev_t*)arg; 144 zx_status_t status; 145 146 while (1) { 147 status = zx_interrupt_wait(dev->irq_handle, NULL); 148 if (status != ZX_OK) { 149 zxlogf(ERROR, "%s: irq wait failed, retcode = %d\n", __FUNCTION__, status); 150 continue; 151 } 152 153 uint32_t reg = I2C_DW_READ32(DW_I2C_RAW_INTR_STAT); 154 if (reg & DW_I2C_INTR_TX_ABRT) { 155 // some sort of error has occured. figure it out 156 i2c_dw_dumpstate(dev); 157 zx_object_signal(dev->event_handle, 0, I2C_ERROR_SIGNAL); 158 zxlogf(ERROR, "i2c: error on bus\n"); 159 } else { 160 zx_object_signal(dev->event_handle, 0, I2C_TXN_COMPLETE_SIGNAL); 161 } 162 i2c_dw_clear_intrrupts(dev); 163 i2c_dw_disable_interrupts(dev); 164 } 165 166 return ZX_OK; 167} 168 169static zx_status_t i2c_dw_transact(void* ctx, uint32_t bus_id, i2c_impl_op_t* rws, size_t count) { 170 size_t i; 171 for (i = 0; i < count; ++i) { 172 if (rws[i].length > I2C_DW_MAX_TRANSFER) { 173 return ZX_ERR_OUT_OF_RANGE; 174 } 175 } 176 177 i2c_dw_t* i2c = ctx; 178 179 if (bus_id >= i2c->i2c_dev_count) { 180 return ZX_ERR_INVALID_ARGS; 181 } 182 183 i2c_dw_dev_t* dev = &i2c->i2c_devs[bus_id]; 184 185 if (count == 0) { 186 return ZX_OK; 187 } 188 for (i = 1; i < count; ++i) { 189 if (rws[i].address != rws[0].address) { 190 return ZX_ERR_NOT_SUPPORTED; 191 } 192 } 193 i2c_dw_set_slave_addr(dev, rws[0].address); 194 i2c_dw_enable(dev); 195 i2c_dw_disable_interrupts(dev); 196 i2c_dw_clear_intrrupts(dev); 197 198 zx_status_t status = ZX_OK; 199 for (i = 0; i < count; ++i) { 200 if (rws[i].is_read) { 201 status = i2c_dw_read(dev, rws[i].buf, rws[i].length, rws[i].stop); 202 } else { 203 status = i2c_dw_write(dev, rws[i].buf, rws[i].length, rws[i].stop); 204 } 205 if (status != ZX_OK) { 206 return status; // TODO(andresoportus) release the bus 207 } 208 } 209 210 i2c_dw_disable_interrupts(dev); 211 i2c_dw_clear_intrrupts(dev); 212 i2c_dw_disable(dev); 213 214 return status; 215} 216 217static zx_status_t i2c_dw_set_bitrate(void* ctx, uint32_t bus_id, uint32_t bitrate) { 218 // TODO: Can't implement due to lack of HI3660 documentation 219 return ZX_ERR_NOT_SUPPORTED; 220} 221 222static uint32_t i2c_dw_get_bus_count(void* ctx) { 223 i2c_dw_t* i2c = ctx; 224 225 return i2c->i2c_dev_count; 226} 227 228static zx_status_t i2c_dw_get_max_transfer_size(void* ctx, uint32_t bus_id, size_t* out_size) { 229 *out_size = I2C_DW_MAX_TRANSFER; 230 return ZX_OK; 231} 232 233static zx_status_t i2c_dw_set_slave_addr(i2c_dw_dev_t* dev, uint16_t addr) { 234 addr &= 0x7f; // support 7bit for now 235 uint32_t reg = I2C_DW_READ32(DW_I2C_TAR); 236 reg = I2C_DW_SET_MASK(reg, DW_I2C_TAR_TAR_START, DW_I2C_TAR_TAR_BITS, addr); 237 reg = I2C_DW_SET_MASK(reg, DW_I2C_TAR_10BIT_START, DW_I2C_TAR_10BIT_BITS, 0); 238 I2C_DW_WRITE32(DW_I2C_TAR, reg); 239 return ZX_OK; 240} 241 242static zx_status_t i2c_dw_read(i2c_dw_dev_t* dev, uint8_t *buff, uint32_t len, bool stop) { 243 uint32_t rx_limit; 244 245 ZX_DEBUG_ASSERT(len <= I2C_DW_MAX_TRANSFER); 246 rx_limit = dev->rx_fifo_depth - I2C_DW_READ32(DW_I2C_RXFLR); 247 ZX_DEBUG_ASSERT(len <= rx_limit); 248 249 // set threshold to the number of bytes we want to read - 1 250 I2C_DW_SET_BITS32(DW_I2C_RX_TL, DW_I2C_RX_TL_START, DW_I2C_RX_TL_BITS, len-1); 251 252 while (len > 0) { 253 uint32_t cmd = 0; 254 // send STOP cmd if last byte and stop set 255 if (len == 1 && stop) { 256 cmd = I2C_DW_SET_MASK(cmd, DW_I2C_DATA_CMD_STOP_START, DW_I2C_DATA_CMD_STOP_BITS, 1); 257 } 258 I2C_DW_WRITE32(DW_I2C_DATA_CMD, cmd | (1 << DW_I2C_DATA_CMD_CMD_START)); 259 len--; 260 } 261 262 i2c_dw_enable_interrupts(dev, DW_I2C_INTR_READ_INTR_MASK); 263 zx_status_t status = i2c_dw_wait_event(dev, I2C_TXN_COMPLETE_SIGNAL); 264 if (status != ZX_OK) { 265 return status; 266 } 267 268 uint32_t avail_read = I2C_DW_READ32(DW_I2C_RXFLR); 269 for (uint32_t i = 0; i < avail_read; i++) { 270 buff[i] = I2C_DW_GET_BITS32(DW_I2C_DATA_CMD, DW_I2C_DATA_CMD_DAT_START, 271 DW_I2C_DATA_CMD_DAT_BITS); 272 } 273 274 return ZX_OK; 275} 276 277static zx_status_t i2c_dw_write(i2c_dw_dev_t* dev, const uint8_t *buff, uint32_t len, bool stop) { 278 uint32_t tx_limit; 279 280 ZX_DEBUG_ASSERT(len <= I2C_DW_MAX_TRANSFER); 281 tx_limit = dev->tx_fifo_depth - I2C_DW_READ32(DW_I2C_TXFLR); 282 ZX_DEBUG_ASSERT(len <= tx_limit); 283 while (len > 0) { 284 uint32_t cmd = 0; 285 // send STOP cmd if last byte and stop set 286 if (len == 1 && stop) { 287 cmd = I2C_DW_SET_MASK(cmd, DW_I2C_DATA_CMD_STOP_START, DW_I2C_DATA_CMD_STOP_BITS, 1); 288 } 289 I2C_DW_WRITE32(DW_I2C_DATA_CMD, cmd | *buff++); 290 len--; 291 } 292 293 // at this point, we have to wait until all data has been transmitted. 294 i2c_dw_enable_interrupts(dev, DW_I2C_INTR_DEFAULT_INTR_MASK); 295 zx_status_t status = i2c_dw_wait_event(dev, I2C_TXN_COMPLETE_SIGNAL); 296 if (status != ZX_OK) { 297 return status; 298 } 299 300 return ZX_OK; 301} 302 303static zx_status_t i2c_dw_host_init(i2c_dw_dev_t* dev) { 304 uint32_t dw_comp_type; 305 uint32_t regval; 306 307 // Make sure we are truly running on a DesignWire IP 308 dw_comp_type = I2C_DW_READ32(DW_I2C_COMP_TYPE); 309 310 if (dw_comp_type != I2C_DW_COMP_TYPE_NUM) { 311 zxlogf(ERROR, "%s: Incompatible IP Block detected. Expected = 0x%x, Actual = 0x%x\n", 312 __FUNCTION__, I2C_DW_COMP_TYPE_NUM, dw_comp_type); 313 314 return ZX_ERR_NOT_SUPPORTED; 315 } 316 317 // read the various capabitlies of the component 318 dev->tx_fifo_depth = I2C_DW_GET_BITS32(DW_I2C_COMP_PARAM_1, 319 DW_I2C_COMP_PARAM_1_TXFIFOSZ_START, 320 DW_I2C_COMP_PARAM_1_TXFIFOSZ_BITS); 321 dev->rx_fifo_depth = I2C_DW_GET_BITS32(DW_I2C_COMP_PARAM_1, 322 DW_I2C_COMP_PARAM_1_RXFIFOSZ_START, 323 DW_I2C_COMP_PARAM_1_RXFIFOSZ_BITS); 324 325 /* I2C Block Initialization based on DW_apb_i2c_databook Section 7.3 */ 326 327 // Disable I2C Block 328 i2c_dw_disable(dev); 329 330 // Configure the controller: 331 // - Slave Disable 332 regval = 0; 333 regval = I2C_DW_SET_MASK(regval, DW_I2C_CON_SLAVE_DIS_START, 334 DW_I2C_CON_SLAVE_DIS_BITS, 335 I2C_ENABLE); 336 337 // - Enable restart mode 338 regval = I2C_DW_SET_MASK(regval, DW_I2C_CON_RESTART_EN_START, 339 DW_I2C_CON_RESTART_EN_BITS, 340 I2C_ENABLE); 341 342 // - Set 7-bit address modeset 343 regval = I2C_DW_SET_MASK(regval, DW_I2C_CON_10BITADDRSLAVE_START, 344 DW_I2C_CON_10BITADDRSLAVE_BITS, 345 I2C_7BIT_ADDR); 346 regval = I2C_DW_SET_MASK(regval, DW_I2C_CON_10BITADDRMASTER_START, 347 DW_I2C_CON_10BITADDRMASTER_BITS, 348 I2C_7BIT_ADDR); 349 350 // - Set speed to fast, master enable 351 regval = I2C_DW_SET_MASK(regval, DW_I2C_CON_SPEED_START, 352 DW_I2C_CON_SPEED_BITS, 353 I2C_FAST_MODE); 354 355 // - Set master enable 356 regval = I2C_DW_SET_MASK(regval, DW_I2C_CON_MASTER_MODE_START, 357 DW_I2C_CON_MASTER_MODE_BITS, 358 I2C_ENABLE); 359 360 // write ifnal mask 361 I2C_DW_WRITE32(DW_I2C_CON, regval); 362 363 // Write SS/FS LCNT and HCNT 364 // FIXME: for now I am using the magical numbers from android source 365 I2C_DW_SET_BITS32(DW_I2C_SS_SCL_HCNT, DW_I2C_SS_SCL_HCNT_START, DW_I2C_SS_SCL_HCNT_BITS, 0x87); 366 I2C_DW_SET_BITS32(DW_I2C_SS_SCL_LCNT, DW_I2C_SS_SCL_LCNT_START, DW_I2C_SS_SCL_LCNT_BITS, 0x9f); 367 I2C_DW_SET_BITS32(DW_I2C_FS_SCL_HCNT, DW_I2C_FS_SCL_HCNT_START, DW_I2C_FS_SCL_HCNT_BITS, 0x1a); 368 I2C_DW_SET_BITS32(DW_I2C_FS_SCL_LCNT, DW_I2C_FS_SCL_LCNT_START, DW_I2C_FS_SCL_LCNT_BITS, 0x32); 369 370 // Setup TX FIFO Thresholds 371 I2C_DW_SET_BITS32(DW_I2C_TX_TL, DW_I2C_TX_TL_START, DW_I2C_TX_TL_BITS, 0); 372 373 // disable interrupts 374 i2c_dw_disable_interrupts(dev); 375 376 return ZX_OK; 377} 378 379static zx_status_t i2c_dw_init(i2c_dw_t* i2c, uint32_t index) { 380 zx_status_t status; 381 382 i2c_dw_dev_t* device = &i2c->i2c_devs[index]; 383 384 device->timeout = ZX_SEC(10); 385 386 status = pdev_map_mmio_buffer2(&i2c->pdev, index, ZX_CACHE_POLICY_UNCACHED_DEVICE, 387 &device->regs_iobuff); 388 if (status != ZX_OK) { 389 zxlogf(ERROR, "%s: pdev_map_mmio_buffer failed %d\n", __FUNCTION__, status); 390 goto init_fail; 391 } 392 393 status = pdev_map_interrupt(&i2c->pdev, index, &device->irq_handle); 394 if (status != ZX_OK) { 395 goto init_fail; 396 } 397 398 status = zx_event_create(0, &device->event_handle); 399 if (status != ZX_OK) { 400 goto init_fail; 401 } 402 403 // initialize i2c host controller 404 status = i2c_dw_host_init(device); 405 if (status != ZX_OK) { 406 zxlogf(ERROR, "%s: failed to initialize i2c host controller %d", __FUNCTION__, status); 407 goto init_fail; 408 } 409 410 thrd_t irq_thread; 411 thrd_create_with_name(&irq_thread, i2c_dw_irq_thread, device, "i2c_dw_irq_thread"); 412 413 return ZX_OK; 414 415init_fail: 416 if (device) { 417 mmio_buffer_release(&device->regs_iobuff); 418 if (device->event_handle != ZX_HANDLE_INVALID) { 419 zx_handle_close(device->event_handle); 420 } 421 if (device->irq_handle != ZX_HANDLE_INVALID) { 422 zx_handle_close(device->irq_handle); 423 } 424 free(device); 425 } 426 return status; 427} 428 429static i2c_impl_protocol_ops_t i2c_ops = { 430 .get_bus_count = i2c_dw_get_bus_count, 431 .get_max_transfer_size = i2c_dw_get_max_transfer_size, 432 .set_bitrate = i2c_dw_set_bitrate, 433 .transact = i2c_dw_transact, 434}; 435 436static zx_protocol_device_t i2c_device_proto = { 437 .version = DEVICE_OPS_VERSION, 438}; 439 440static zx_status_t dw_i2c_bind(void* ctx, zx_device_t* parent) { 441 printf("dw_i2c_bind\n"); 442 zx_status_t status; 443 444 i2c_dw_t* i2c = calloc(1, sizeof(i2c_dw_t)); 445 if (!i2c) { 446 return ZX_ERR_NO_MEMORY; 447 } 448 449 if ((status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_DEV, &i2c->pdev)) != ZX_OK) { 450 zxlogf(ERROR, "dw_i2c_bind: ZX_PROTOCOL_PLATFORM_DEV not available\n"); 451 goto fail; 452 } 453 454 platform_bus_protocol_t pbus; 455 if ((status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_BUS, &pbus)) != ZX_OK) { 456 zxlogf(ERROR, "dw_i2c_bind: ZX_PROTOCOL_PLATFORM_BUS not available\n"); 457 goto fail; 458 } 459 460 pdev_device_info_t info; 461 status = pdev_get_device_info(&i2c->pdev, &info); 462 if (status != ZX_OK) { 463 zxlogf(ERROR, "dw_i2c_bind: pdev_get_device_info failed\n"); 464 goto fail; 465 } 466 467 if (info.mmio_count != info.irq_count) { 468 zxlogf(ERROR, "dw_i2c_bind: mmio_count %u does not matchirq_count %u\n", 469 info.mmio_count, info.irq_count); 470 status = ZX_ERR_INVALID_ARGS; 471 goto fail; 472 } 473 474 i2c->i2c_devs = calloc(info.mmio_count, sizeof(i2c_dw_dev_t)); 475 if (!i2c->i2c_devs) { 476 free(i2c); 477 return ZX_ERR_NO_MEMORY; 478 } 479 i2c->i2c_dev_count = info.mmio_count; 480 481 for (uint32_t i = 0; i < i2c->i2c_dev_count; i++) { 482 zx_status_t status = i2c_dw_init(i2c, i); 483 if (status != ZX_OK) { 484 zxlogf(ERROR, "dw_i2c_bind: dw_i2c_dev_init failed: %d\n", status); 485 goto fail; 486 } 487 } 488 489 device_add_args_t args = { 490 .version = DEVICE_ADD_ARGS_VERSION, 491 .name = "dw-i2c", 492 .ctx = i2c, 493 .ops = &i2c_device_proto, 494 .flags = DEVICE_ADD_NON_BINDABLE, 495 }; 496 497 status = device_add(parent, &args, &i2c->zxdev); 498 if (status != ZX_OK) { 499 zxlogf(ERROR, "dw_i2c_bind: device_add failed\n"); 500 goto fail; 501 } 502 503 i2c->i2c.ops = &i2c_ops; 504 i2c->i2c.ctx = i2c; 505 pbus_register_protocol(&pbus, ZX_PROTOCOL_I2C_IMPL, &i2c->i2c, NULL, NULL); 506 507 return ZX_OK; 508 509fail: 510 return status; 511} 512 513static zx_driver_ops_t dw_i2c_driver_ops = { 514 .version = DRIVER_OPS_VERSION, 515 .bind = dw_i2c_bind, 516}; 517 518ZIRCON_DRIVER_BEGIN(dw_i2c, dw_i2c_driver_ops, "zircon", "0.1", 4) 519 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PLATFORM_DEV), 520 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_GENERIC), 521 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_GENERIC), 522 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_DW_I2C), 523ZIRCON_DRIVER_END(dw_i2c) 524