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 <stdint.h>
6 #include <threads.h>
7
8 #include <bits/limits.h>
9 #include <ddk/binding.h>
10 #include <ddk/debug.h>
11 #include <ddk/device.h>
12 #include <ddk/mmio-buffer.h>
13 #include <ddk/platform-defs.h>
14 #include <ddk/protocol/gpioimpl.h>
15 #include <ddk/protocol/platform/bus.h>
16 #include <ddk/protocol/platform/device.h>
17 #include <ddk/protocol/platform-device-lib.h>
18 #include <hw/reg.h>
19
20 #include <zircon/assert.h>
21 #include <zircon/types.h>
22
23 #define ALT_FUNCTION_MAX 15
24 #define GPIO_INTERRUPT_POLARITY_SHIFT 16
25 #define MAX_GPIO_INDEX 255
26 #define BITS_PER_GPIO_INTERRUPT 8
27 #define BITS_PER_FILTER_SELECT 4
28
29 #define READ32_GPIO_REG(index, offset) \
30 readl((uint32_t*)gpio->mmios[index].vaddr + offset)
31 #define WRITE32_GPIO_REG(index, offset, value) \
32 writel(value, (uint32_t*)gpio->mmios[index].vaddr + offset)
33
34 #define READ32_GPIO_INTERRUPT_REG(offset) \
35 readl((uint32_t*)gpio->mmio_interrupt.vaddr + offset)
36 #define WRITE32_GPIO_INTERRUPT_REG(offset, value) \
37 writel(value, (uint32_t*)gpio->mmio_interrupt.vaddr + offset)
38
39
40 typedef struct {
41 uint32_t start_pin;
42 uint32_t pin_block;
43 uint32_t pin_count;
44 uint32_t mux_offset;
45 uint32_t oen_offset;
46 uint32_t input_offset;
47 uint32_t output_offset;
48 uint32_t output_shift; // Used for GPIOAO block
49 uint32_t mmio_index;
50 uint32_t pull_offset;
51 uint32_t pull_en_offset;
52 uint32_t pin_start;
53 mtx_t lock;
54 } aml_gpio_block_t;
55
56 typedef struct {
57 uint32_t pin_0_3_select_offset;
58 uint32_t pin_4_7_select_offset;
59 uint32_t edge_polarity_offset;
60 uint32_t filter_select_offset;
61 uint32_t status_offset;
62 uint32_t mask_offset;
63 uint32_t irq_count;
64 uint16_t *irq_info;
65 mtx_t lock;
66 uint8_t irq_status;
67 } aml_gpio_interrupt_t;
68
69 typedef struct {
70 pdev_protocol_t pdev;
71 gpio_impl_protocol_t gpio;
72 zx_device_t* zxdev;
73 mmio_buffer_t mmios[2]; // separate MMIO for AO domain
74 mmio_buffer_t mmio_interrupt;
75 aml_gpio_block_t* gpio_blocks;
76 aml_gpio_interrupt_t* gpio_interrupt;
77 size_t block_count;
78 } aml_gpio_t;
79
80 // MMIO indices (based on aml-gpio.c gpio_mmios)
81 enum {
82 MMIO_GPIO = 0,
83 MMIO_GPIO_A0 = 1,
84 MMIO_GPIO_INTERRUPTS = 2,
85 };
86 #include "a113-blocks.h"
87 #include "s905d2-blocks.h"
88
aml_pin_to_block(aml_gpio_t * gpio,const uint32_t pin,aml_gpio_block_t ** result)89 static zx_status_t aml_pin_to_block(aml_gpio_t* gpio, const uint32_t pin, aml_gpio_block_t** result) {
90 ZX_DEBUG_ASSERT(result);
91
92 for (size_t i = 0; i < gpio->block_count; i++) {
93 aml_gpio_block_t* gpio_block = &gpio->gpio_blocks[i];
94 const uint32_t end_pin = gpio_block->start_pin + gpio_block->pin_count;
95 if (pin >= gpio_block->start_pin && pin < end_pin) {
96 *result = gpio_block;
97 return ZX_OK;
98 }
99 }
100
101 return ZX_ERR_NOT_FOUND;
102 }
103
aml_gpio_config_in(void * ctx,uint32_t index,uint32_t flags)104 static zx_status_t aml_gpio_config_in(void* ctx, uint32_t index, uint32_t flags) {
105 aml_gpio_t* gpio = ctx;
106 zx_status_t status;
107
108 aml_gpio_block_t* block;
109 if ((status = aml_pin_to_block(gpio, index, &block)) != ZX_OK) {
110 zxlogf(ERROR, "aml_gpio_config: pin not found %u\n", index);
111 return status;
112 }
113
114 uint32_t pinindex = index - block->pin_block;
115 pinindex += block->output_shift;
116 const uint32_t pinmask = 1 << pinindex;
117
118 mtx_lock(&block->lock);
119
120 uint32_t regval = READ32_GPIO_REG(block->mmio_index, block->oen_offset);
121 // Set the GPIO as pull-up or pull-down
122 uint32_t pull = flags & GPIO_PULL_MASK;
123 uint32_t pull_reg_val = READ32_GPIO_REG(block->mmio_index, block->pull_offset);
124 uint32_t pull_en_reg_val = READ32_GPIO_REG(block->mmio_index, block->pull_en_offset);
125 if (pull & GPIO_NO_PULL) {
126 pull_en_reg_val &= ~pinmask;
127 } else {
128 if (pull & GPIO_PULL_UP) {
129 pull_reg_val |= pinmask;
130 } else {
131 pull_reg_val &= ~pinmask;
132 }
133 pull_en_reg_val |= pinmask;
134 }
135
136 WRITE32_GPIO_REG(block->mmio_index, block->pull_offset, pull_reg_val);
137 WRITE32_GPIO_REG(block->mmio_index, block->pull_en_offset, pull_en_reg_val);
138 regval |= pinmask;
139 WRITE32_GPIO_REG(block->mmio_index, block->oen_offset, regval);
140
141 mtx_unlock(&block->lock);
142
143 return ZX_OK;
144 }
145
aml_gpio_config_out(void * ctx,uint32_t index,uint8_t initial_value)146 static zx_status_t aml_gpio_config_out(void* ctx, uint32_t index, uint8_t initial_value) {
147 aml_gpio_t* gpio = ctx;
148 zx_status_t status;
149
150 aml_gpio_block_t* block;
151 if ((status = aml_pin_to_block(gpio, index, &block)) != ZX_OK) {
152 zxlogf(ERROR, "aml_gpio_config: pin not found %u\n", index);
153 return status;
154 }
155
156 uint32_t pinindex = index - block->pin_block;
157 pinindex += block->output_shift;
158 const uint32_t pinmask = 1 << pinindex;
159
160 mtx_lock(&block->lock);
161
162 // Set value before configuring for output
163 uint32_t regval = READ32_GPIO_REG(block->mmio_index, block->output_offset);
164 if (initial_value) {
165 regval |= pinmask;
166 } else {
167 regval &= ~pinmask;
168 }
169 WRITE32_GPIO_REG(block->mmio_index, block->output_offset, regval);
170
171 regval = READ32_GPIO_REG(block->mmio_index, block->oen_offset);
172 regval &= ~pinmask;
173 WRITE32_GPIO_REG(block->mmio_index, block->oen_offset, regval);
174
175 mtx_unlock(&block->lock);
176
177 return ZX_OK;
178 }
179
180 // Configure a pin for an alternate function specified by fn
aml_gpio_set_alt_function(void * ctx,const uint32_t pin,const uint64_t fn)181 static zx_status_t aml_gpio_set_alt_function(void* ctx, const uint32_t pin, const uint64_t fn) {
182 aml_gpio_t* gpio = ctx;
183
184 if (fn > ALT_FUNCTION_MAX) {
185 zxlogf(ERROR, "aml_config_pinmux: pin mux alt config out of range"
186 " %lu\n", fn);
187 return ZX_ERR_OUT_OF_RANGE;
188 }
189
190 zx_status_t status;
191
192 aml_gpio_block_t* block;
193 if (((status = aml_pin_to_block(gpio, pin, &block)) != ZX_OK) != ZX_OK) {
194 zxlogf(ERROR, "aml_config_pinmux: pin not found %u\n", pin);
195 return status;
196 }
197
198 // Sanity Check: pin_to_block must return a block that contains `pin`
199 // therefore `pin` must be greater than or equal to the first
200 // pin of the block.
201 ZX_DEBUG_ASSERT(pin >= block->start_pin);
202
203 // Each Pin Mux is controlled by a 4 bit wide field in `reg`
204 // Compute the offset for this pin.
205 uint32_t pin_shift = (pin - block->start_pin) * 4;
206 pin_shift += block->output_shift;
207 const uint32_t mux_mask = ~(0x0F << pin_shift);
208 const uint32_t fn_val = fn << pin_shift;
209
210 mtx_lock(&block->lock);
211
212 uint32_t regval = READ32_GPIO_REG(block->mmio_index, block->mux_offset);
213 regval &= mux_mask; // Remove the previous value for the mux
214 regval |= fn_val; // Assign the new value to the mux
215 WRITE32_GPIO_REG(block->mmio_index, block->mux_offset, regval);
216
217 mtx_unlock(&block->lock);
218
219 return ZX_OK;
220 }
221
aml_gpio_read(void * ctx,uint32_t index,uint8_t * out_value)222 static zx_status_t aml_gpio_read(void* ctx, uint32_t index, uint8_t* out_value) {
223 aml_gpio_t* gpio = ctx;
224 zx_status_t status;
225
226 aml_gpio_block_t* block;
227 if ((status = aml_pin_to_block(gpio, index, &block)) != ZX_OK) {
228 zxlogf(ERROR, "aml_config_pinmux: pin not found %u\n", index);
229 return status;
230 }
231
232 uint32_t pinindex = index - block->pin_block;
233 pinindex += block->output_shift;
234 const uint32_t readmask = 1 << pinindex;
235 mtx_lock(&block->lock);
236
237 const uint32_t regval = READ32_GPIO_REG(block->mmio_index, block->input_offset);
238
239 mtx_unlock(&block->lock);
240
241 if (regval & readmask) {
242 *out_value = 1;
243 } else {
244 *out_value = 0;
245 }
246
247 return ZX_OK;
248 }
249
aml_gpio_write(void * ctx,uint32_t index,uint8_t value)250 static zx_status_t aml_gpio_write(void* ctx, uint32_t index, uint8_t value) {
251 aml_gpio_t* gpio = ctx;
252 zx_status_t status;
253
254 aml_gpio_block_t* block;
255 if ((status = aml_pin_to_block(gpio, index, &block)) != ZX_OK) {
256 zxlogf(ERROR, "aml_gpio_write: pin not found %u\n", index);
257 return status;
258 }
259
260 uint32_t pinindex = index - block->pin_block;
261 pinindex += block->output_shift;
262
263 mtx_lock(&block->lock);
264
265 uint32_t regval = READ32_GPIO_REG(block->mmio_index, block->output_offset);
266 if (value) {
267 regval |= 1 << pinindex;
268 } else {
269 regval &= ~(1 << pinindex);
270 }
271 WRITE32_GPIO_REG(block->mmio_index, block->output_offset, regval);
272
273 mtx_unlock(&block->lock);
274
275 return ZX_OK;
276 }
277
aml_gpio_get_unsed_irq_index(uint8_t status)278 static uint32_t aml_gpio_get_unsed_irq_index(uint8_t status) {
279 // First isolate the rightmost 0-bit
280 uint8_t zero_bit_set = ~status & (status+1);
281 // Count no. of leading zeros
282 return __builtin_ctz(zero_bit_set);
283 }
284
aml_gpio_get_interrupt(void * ctx,uint32_t pin,uint32_t flags,zx_handle_t * out_handle)285 static zx_status_t aml_gpio_get_interrupt(void *ctx, uint32_t pin,
286 uint32_t flags,
287 zx_handle_t *out_handle) {
288 aml_gpio_t* gpio = ctx;
289 zx_status_t status = ZX_OK;
290 aml_gpio_interrupt_t* interrupt = gpio->gpio_interrupt;
291
292 if (pin > MAX_GPIO_INDEX) {
293 return ZX_ERR_INVALID_ARGS;
294 }
295 mtx_lock(&interrupt->lock);
296
297 uint32_t index = aml_gpio_get_unsed_irq_index(interrupt->irq_status);
298 if (index > interrupt->irq_count) {
299 status = ZX_ERR_NO_RESOURCES;
300 goto fail;
301 }
302
303 for (uint32_t i=0; i<interrupt->irq_count; i++) {
304 if(interrupt->irq_info[i] == pin) {
305 zxlogf(ERROR, "GPIO Interrupt already configured for this pin %u\n", (int)index);
306 status = ZX_ERR_ALREADY_EXISTS;
307 goto fail;
308 }
309 }
310 zxlogf(INFO, "GPIO Interrupt index %d allocated\n", (int)index);
311 aml_gpio_block_t* block;
312 if ((status = aml_pin_to_block(gpio, pin, &block)) != ZX_OK) {
313 zxlogf(ERROR, "aml_gpio_read: pin not found %u\n", pin);
314 goto fail;
315 }
316 uint32_t flags_ = flags;
317 if (flags == ZX_INTERRUPT_MODE_EDGE_LOW) {
318 // GPIO controller sets the polarity
319 flags_ = ZX_INTERRUPT_MODE_EDGE_HIGH;
320 } else if (flags == ZX_INTERRUPT_MODE_LEVEL_LOW) {
321 flags_ = ZX_INTERRUPT_MODE_LEVEL_HIGH;
322 }
323
324 // Create Interrupt Object
325 status = pdev_get_interrupt(&gpio->pdev, index, flags_,
326 out_handle);
327 if (status != ZX_OK) {
328 zxlogf(ERROR, "aml_gpio_get_interrupt: pdev_map_interrupt failed %d\n", status);
329 goto fail;
330 }
331
332 // Configure GPIO interrupt
333 uint32_t pin_select_offset = ((index>3)? interrupt->pin_4_7_select_offset: interrupt->pin_0_3_select_offset);
334 // Select GPIO IRQ(index) and program it to
335 // the requested GPIO PIN
336 RMWREG32((uint32_t*)gpio->mmio_interrupt.vaddr + pin_select_offset,
337 index * BITS_PER_GPIO_INTERRUPT, BITS_PER_GPIO_INTERRUPT,
338 (pin - block->pin_block) + block->pin_start);
339 // Configure GPIO Interrupt EDGE and Polarity
340 uint32_t mode_reg_val = READ32_GPIO_INTERRUPT_REG(interrupt->edge_polarity_offset);
341
342 switch (flags & ZX_INTERRUPT_MODE_MASK) {
343 case ZX_INTERRUPT_MODE_EDGE_LOW:
344 mode_reg_val = mode_reg_val | (1 << index);
345 mode_reg_val = mode_reg_val | ((1 << index) << GPIO_INTERRUPT_POLARITY_SHIFT);
346 break;
347 case ZX_INTERRUPT_MODE_EDGE_HIGH:
348 mode_reg_val = mode_reg_val | (1 << index);
349 mode_reg_val = mode_reg_val & ~((1 << index) << GPIO_INTERRUPT_POLARITY_SHIFT);
350 break;
351 case ZX_INTERRUPT_MODE_LEVEL_LOW:
352 mode_reg_val = mode_reg_val & ~(1 << index);
353 mode_reg_val = mode_reg_val | ((1 << index) << GPIO_INTERRUPT_POLARITY_SHIFT);
354 break;
355 case ZX_INTERRUPT_MODE_LEVEL_HIGH:
356 mode_reg_val = mode_reg_val & ~(1 << index);
357 mode_reg_val = mode_reg_val & ~((1 << index) << GPIO_INTERRUPT_POLARITY_SHIFT);
358 break;
359 default:
360 status = ZX_ERR_INVALID_ARGS;
361 goto fail;
362 }
363 WRITE32_GPIO_INTERRUPT_REG(interrupt->edge_polarity_offset, mode_reg_val);
364
365 // Configure Interrupt Select Filter
366 uint32_t regval = READ32_GPIO_INTERRUPT_REG(interrupt->filter_select_offset);
367 WRITE32_GPIO_INTERRUPT_REG(interrupt->filter_select_offset,
368 regval | (0x7 << (index * BITS_PER_FILTER_SELECT)));
369 interrupt->irq_status |= 1 << index;
370 interrupt->irq_info[index] = pin;
371 fail:
372 mtx_unlock(&interrupt->lock);
373 return status;
374 }
375
aml_gpio_release_interrupt(void * ctx,uint32_t pin)376 static zx_status_t aml_gpio_release_interrupt(void *ctx, uint32_t pin) {
377 aml_gpio_t* gpio = ctx;
378 aml_gpio_interrupt_t* interrupt = gpio->gpio_interrupt;
379 mtx_lock(&interrupt->lock);
380 for (uint32_t i=0; i<interrupt->irq_count; i++) {
381 if(interrupt->irq_info[i] == pin) {
382 interrupt->irq_status &= ~(1 << i);
383 interrupt->irq_info[i] = MAX_GPIO_INDEX+1;
384 mtx_unlock(&interrupt->lock);
385 return ZX_OK;
386 }
387 }
388 mtx_unlock(&interrupt->lock);
389 return ZX_ERR_NOT_FOUND;
390 }
391
aml_gpio_set_polarity(void * ctx,uint32_t pin,uint32_t polarity)392 static zx_status_t aml_gpio_set_polarity(void *ctx, uint32_t pin,
393 uint32_t polarity) {
394 aml_gpio_t* gpio = ctx;
395 aml_gpio_interrupt_t* interrupt = gpio->gpio_interrupt;
396 int irq_index = -1;
397 if (pin > MAX_GPIO_INDEX) {
398 return ZX_ERR_INVALID_ARGS;
399 }
400
401 for (uint32_t i=0; i<interrupt->irq_count; i++) {
402 if(interrupt->irq_info[i] == pin) {
403 irq_index = i;
404 break;
405 }
406 }
407 if (irq_index == -1) {
408 return ZX_ERR_NOT_FOUND;
409 }
410
411 mtx_lock(&interrupt->lock);
412 // Configure GPIO Interrupt EDGE and Polarity
413 uint32_t mode_reg_val = READ32_GPIO_INTERRUPT_REG(interrupt->edge_polarity_offset);
414 if (polarity) {
415 mode_reg_val &= ~((1 << irq_index) << GPIO_INTERRUPT_POLARITY_SHIFT);
416 } else {
417 mode_reg_val |= ((1 << irq_index) << GPIO_INTERRUPT_POLARITY_SHIFT);
418 }
419 WRITE32_GPIO_INTERRUPT_REG(interrupt->edge_polarity_offset, mode_reg_val);
420 mtx_unlock(&interrupt->lock);
421 return ZX_OK;
422 }
423
424 static gpio_impl_protocol_ops_t gpio_ops = {
425 .config_in = aml_gpio_config_in,
426 .config_out = aml_gpio_config_out,
427 .set_alt_function = aml_gpio_set_alt_function,
428 .read = aml_gpio_read,
429 .write = aml_gpio_write,
430 .get_interrupt = aml_gpio_get_interrupt,
431 .release_interrupt = aml_gpio_release_interrupt,
432 .set_polarity = aml_gpio_set_polarity,
433 };
434
aml_gpio_release(void * ctx)435 static void aml_gpio_release(void* ctx) {
436 aml_gpio_t* gpio = ctx;
437 mmio_buffer_release(&gpio->mmios[MMIO_GPIO]);
438 mmio_buffer_release(&gpio->mmios[MMIO_GPIO_A0]);
439 mmio_buffer_release(&gpio->mmio_interrupt);
440 free(gpio->gpio_interrupt->irq_info);
441 free(gpio);
442 }
443
444
445 static zx_protocol_device_t gpio_device_proto = {
446 .version = DEVICE_OPS_VERSION,
447 .release = aml_gpio_release,
448 };
449
aml_gpio_bind(void * ctx,zx_device_t * parent)450 static zx_status_t aml_gpio_bind(void* ctx, zx_device_t* parent) {
451 zx_status_t status;
452
453 aml_gpio_t* gpio = calloc(1, sizeof(aml_gpio_t));
454 if (!gpio) {
455 return ZX_ERR_NO_MEMORY;
456 }
457
458 if ((status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &gpio->pdev)) != ZX_OK) {
459 zxlogf(ERROR, "aml_gpio_bind: ZX_PROTOCOL_PDEV not available\n");
460 goto fail;
461 }
462
463 pbus_protocol_t pbus;
464 if ((status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &pbus)) != ZX_OK) {
465 zxlogf(ERROR, "aml_gpio_bind: ZX_PROTOCOL_PBUS not available\n");
466 goto fail;
467 }
468
469 status = pdev_map_mmio_buffer2(&gpio->pdev, MMIO_GPIO, ZX_CACHE_POLICY_UNCACHED_DEVICE,
470 &gpio->mmios[MMIO_GPIO]);
471 if (status != ZX_OK) {
472 zxlogf(ERROR, "aml_gpio_bind: pdev_map_mmio_buffer failed\n");
473 goto fail;
474 }
475
476 status = pdev_map_mmio_buffer2(&gpio->pdev, MMIO_GPIO_A0, ZX_CACHE_POLICY_UNCACHED_DEVICE,
477 &gpio->mmios[MMIO_GPIO_A0]);
478 if (status != ZX_OK) {
479 zxlogf(ERROR, "aml_gpio_bind: pdev_map_mmio_buffer failed\n");
480 goto fail;
481 }
482
483 status = pdev_map_mmio_buffer2(&gpio->pdev, MMIO_GPIO_INTERRUPTS, ZX_CACHE_POLICY_UNCACHED_DEVICE,
484 &gpio->mmio_interrupt);
485 if (status != ZX_OK) {
486 zxlogf(ERROR, "aml_gpio_bind: pdev_map_mmio_buffer failed\n");
487 goto fail;
488 }
489
490 pdev_device_info_t info;
491 status = pdev_get_device_info(&gpio->pdev, &info);
492 if (status != ZX_OK) {
493 zxlogf(ERROR, "aml_gpio_bind: pdev_get_device_info failed\n");
494 goto fail;
495 }
496
497 switch (info.pid) {
498 case PDEV_PID_AMLOGIC_A113:
499 gpio->gpio_blocks = a113_gpio_blocks;
500 gpio->block_count = countof(a113_gpio_blocks);
501 gpio->gpio_interrupt = &a113_interrupt_block;
502 break;
503 case PDEV_PID_AMLOGIC_S905D2:
504 case PDEV_PID_AMLOGIC_T931:
505 // S905D2 and T931 are identical.
506 gpio->gpio_blocks = s905d2_gpio_blocks;
507 gpio->block_count = countof(s905d2_gpio_blocks);
508 gpio->gpio_interrupt = &s905d2_interrupt_block;
509 break;
510 default:
511 zxlogf(ERROR, "aml_gpio_bind: unsupported SOC PID %u\n", info.pid);
512 status = ZX_ERR_INVALID_ARGS;
513 goto fail;
514 }
515
516 device_add_args_t args = {
517 .version = DEVICE_ADD_ARGS_VERSION,
518 .name = "aml-axg-gpio",
519 .ctx = gpio,
520 .ops = &gpio_device_proto,
521 .flags = DEVICE_ADD_NON_BINDABLE,
522 };
523
524 status = device_add(parent, &args, &gpio->zxdev);
525 if (status != ZX_OK) {
526 zxlogf(ERROR, "aml_gpio_bind: device_add failed\n");
527 goto fail;
528 }
529
530 gpio->gpio_interrupt->irq_count = info.irq_count;
531 gpio->gpio_interrupt->irq_status = 0;
532 gpio->gpio.ops = &gpio_ops;
533 gpio->gpio.ctx = gpio;
534 const platform_proxy_cb_t kCallback = {NULL, NULL};
535 pbus_register_protocol(&pbus, ZX_PROTOCOL_GPIO_IMPL, &gpio->gpio, sizeof(gpio->gpio),
536 &kCallback);
537 gpio->gpio_interrupt->irq_info = calloc(gpio->gpio_interrupt->irq_count,
538 sizeof(uint16_t));
539 if (!gpio->gpio_interrupt->irq_info) {
540 zxlogf(ERROR, "aml_gpio_bind: irq_info calloc failed\n");
541 goto fail;
542 }
543
544 return ZX_OK;
545
546 fail:
547 aml_gpio_release(gpio);
548 return status;
549 }
550
551 static zx_driver_ops_t aml_gpio_driver_ops = {
552 .version = DRIVER_OPS_VERSION,
553 .bind = aml_gpio_bind,
554 };
555
556 ZIRCON_DRIVER_BEGIN(aml_gpio, aml_gpio_driver_ops, "zircon", "0.1", 6)
557 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PDEV),
558 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_AMLOGIC),
559 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_GPIO),
560 // we support multiple SOC variants
561 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_A113),
562 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_S905D2),
563 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_T931),
564 ZIRCON_DRIVER_END(aml_gpio)
565