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