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