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