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