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