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/platform-defs.h>
8 #include <ddk/protocol/platform/bus.h>
9 
10 #include <soc/aml-t931/t931-gpio.h>
11 #include <soc/aml-t931/t931-hw.h>
12 
13 #include "sherlock.h"
14 
15 namespace sherlock {
16 
17 static const pbus_mmio_t gpio_mmios[] = {
18     {
19         .base = T931_GPIO_BASE,
20         .length = T931_GPIO_LENGTH,
21     },
22     {
23         .base = T931_GPIO_A0_BASE,
24         .length = T931_GPIO_AO_LENGTH,
25     },
26     {
27         .base = T931_GPIO_INTERRUPT_BASE,
28         .length = T931_GPIO_INTERRUPT_LENGTH,
29     },
30 };
31 
32 static const pbus_irq_t gpio_irqs[] = {
33     {
34         .irq = T931_GPIO_IRQ_0,
35         .mode = ZX_INTERRUPT_MODE_DEFAULT,
36     },
37     {
38         .irq = T931_GPIO_IRQ_1,
39         .mode = ZX_INTERRUPT_MODE_DEFAULT,
40     },
41     {
42         .irq = T931_GPIO_IRQ_2,
43         .mode = ZX_INTERRUPT_MODE_DEFAULT,
44     },
45     {
46         .irq = T931_GPIO_IRQ_3,
47         .mode = ZX_INTERRUPT_MODE_DEFAULT,
48     },
49     {
50         .irq = T931_GPIO_IRQ_4,
51         .mode = ZX_INTERRUPT_MODE_DEFAULT,
52     },
53     {
54         .irq = T931_GPIO_IRQ_5,
55         .mode = ZX_INTERRUPT_MODE_DEFAULT,
56     },
57     {
58         .irq = T931_GPIO_IRQ_6,
59         .mode = ZX_INTERRUPT_MODE_DEFAULT,
60     },
61     {
62         .irq = T931_GPIO_IRQ_7,
63         .mode = ZX_INTERRUPT_MODE_DEFAULT,
64     },
65 };
66 
__anon467c39760102()67 static pbus_dev_t gpio_dev = [](){
68     pbus_dev_t dev;
69     dev.name = "gpio";
70     dev.vid = PDEV_VID_AMLOGIC;
71     dev.pid = PDEV_PID_AMLOGIC_T931;
72     dev.did = PDEV_DID_AMLOGIC_GPIO;
73     dev.mmio_list = gpio_mmios;
74     dev.mmio_count = countof(gpio_mmios);
75     dev.irq_list = gpio_irqs;
76     dev.irq_count = countof(gpio_irqs);
77     return dev;
78 }();
79 
GpioInit()80 zx_status_t Sherlock::GpioInit() {
81     zx_status_t status = pbus_.ProtocolDeviceAdd(ZX_PROTOCOL_GPIO_IMPL, &gpio_dev);
82     if (status != ZX_OK) {
83         zxlogf(ERROR, "%s: ProtocolDeviceAdd failed %d\n", __func__, status);
84         return status;
85     }
86 // This test binds to system/dev/gpio/gpio-test to check that GPIOs work at all.
87 // gpio-test enables interrupts and write/read on the test GPIOs configured below.
88 //#define GPIO_TEST
89 #ifdef GPIO_TEST
90     const pbus_gpio_t gpio_test_gpios[] = {
91         {
92             .gpio = T931_GPIOZ(5), // Volume down, not used in this test.
93         },
94         {
95             .gpio = T931_GPIOZ(4), // Volume up, to test gpio_get_interrupt().
96         },
97     };
98 
99     pbus_dev_t gpio_test_dev = {};
100     gpio_test_dev.name = "sherlock-gpio-test";
101     gpio_test_dev.vid = PDEV_VID_GENERIC;
102     gpio_test_dev.pid = PDEV_PID_GENERIC;
103     gpio_test_dev.did = PDEV_DID_GPIO_TEST;
104     gpio_test_dev.gpio_list = gpio_test_gpios;
105     gpio_test_dev.gpio_count = countof(gpio_test_gpios);
106     if ((status = pbus_.DeviceAdd(&gpio_test_dev)) != ZX_OK) {
107         zxlogf(ERROR, "%s: Could not add gpio_test_dev %d\n", __FUNCTION__, status);
108         return status;
109     }
110 #endif
111 
112     gpio_impl_ = ddk::GpioImplProtocolClient(parent());
113     if (!gpio_impl_.is_valid()) {
114         zxlogf(ERROR, "%s: device_get_protocol failed %d\n", __func__, status);
115         return ZX_ERR_INTERNAL;
116     }
117 
118     return ZX_OK;
119 }
120 
121 } // namespace sherlock
122