1// Copyright 2018 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/debug.h>
6#include <ddk/device.h>
7#include <ddk/protocol/platform-bus.h>
8#include <ddk/protocol/platform-defs.h>
9
10#include <soc/aml-s905d2/s905d2-gpio.h>
11#include <soc/aml-s905d2/s905d2-hw.h>
12
13#include <limits.h>
14
15#include "astro.h"
16
17// uncomment to disable LED blinky test
18// #define GPIO_TEST 1
19
20static const pbus_mmio_t gpio_mmios[] = {
21    {
22        .base = S905D2_GPIO_BASE,
23        .length = S905D2_GPIO_LENGTH,
24    },
25    {
26        .base = S905D2_GPIO_A0_BASE,
27        .length = S905D2_GPIO_AO_LENGTH,
28    },
29    {
30        .base = S905D2_GPIO_INTERRUPT_BASE,
31        .length = S905D2_GPIO_INTERRUPT_LENGTH,
32    },
33};
34
35static const pbus_irq_t gpio_irqs[] = {
36    {
37        .irq = S905D2_GPIO_IRQ_0,
38    },
39    {
40        .irq = S905D2_GPIO_IRQ_1,
41    },
42    {
43        .irq = S905D2_GPIO_IRQ_2,
44    },
45    {
46        .irq = S905D2_GPIO_IRQ_3,
47    },
48    {
49        .irq = S905D2_GPIO_IRQ_4,
50    },
51    {
52        .irq = S905D2_GPIO_IRQ_5,
53    },
54    {
55        .irq = S905D2_GPIO_IRQ_6,
56    },
57    {
58        .irq = S905D2_GPIO_IRQ_7,
59    },
60    /*
61    {
62        .irq = S905D2_A0_GPIO_IRQ_0,
63        .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
64    },
65    {
66        .irq = S905D2_A0_GPIO_IRQ_1,
67        .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
68    },
69    */
70};
71
72static pbus_dev_t gpio_dev = {
73    .name = "gpio",
74    .vid = PDEV_VID_AMLOGIC,
75    .pid = PDEV_PID_AMLOGIC_S905D2,
76    .did = PDEV_DID_AMLOGIC_GPIO,
77    .mmios = gpio_mmios,
78    .mmio_count = countof(gpio_mmios),
79    .irqs = gpio_irqs,
80    .irq_count = countof(gpio_irqs),
81};
82
83zx_status_t aml_gpio_init(aml_bus_t* bus) {
84    zx_status_t status = pbus_protocol_device_add(&bus->pbus, ZX_PROTOCOL_GPIO_IMPL, &gpio_dev);
85    if (status != ZX_OK) {
86        zxlogf(ERROR, "aml_gpio_init: pbus_protocol_device_add failed: %d\n", status);
87        return status;
88    }
89
90    status = device_get_protocol(bus->parent, ZX_PROTOCOL_GPIO_IMPL, &bus->gpio);
91    if (status != ZX_OK) {
92        zxlogf(ERROR, "aml_gpio_init: device_get_protocol failed: %d\n", status);
93        return status;
94    }
95
96#if GPIO_TEST
97    const pbus_gpio_t gpio_test_gpios[] = {
98        {
99            // SYS_LED
100            .gpio = S905D2_GPIOAO(11),
101        },
102        {
103            // JTAG Adapter Pin
104            .gpio = S905D2_GPIOAO(6),
105        }
106    };
107
108    const pbus_dev_t gpio_test_dev = {
109        .name = "aml-gpio-test",
110        .vid = PDEV_VID_GENERIC,
111        .pid = PDEV_PID_GENERIC,
112        .did = PDEV_DID_GPIO_TEST,
113        .gpios = gpio_test_gpios,
114        .gpio_count = countof(gpio_test_gpios),
115    };
116
117    if ((status = pbus_device_add(&bus->pbus, &gpio_test_dev, 0)) != ZX_OK) {
118        zxlogf(ERROR, "aml_gpio_init could not add gpio_test_dev: %d\n", status);
119        return status;
120    }
121#endif
122
123    return ZX_OK;
124}
125