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 <assert.h>
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <threads.h>
11#include <unistd.h>
12
13#include <ddk/binding.h>
14#include <ddk/debug.h>
15#include <ddk/device.h>
16#include <ddk/driver.h>
17#include <ddk/protocol/platform-defs.h>
18#include <gpio/pl061/pl061.h>
19
20#include <zircon/process.h>
21#include <zircon/syscalls.h>
22#include <zircon/assert.h>
23
24#include <soc/hi3660/hi3660.h>
25#include <soc/hi3660/hi3660-hw.h>
26#include <soc/hi3660/hi3660-regs.h>
27#include <hw/reg.h>
28
29zx_status_t hi3660_enable_ldo3(hi3660_t* hi3660) {
30    volatile void* iopmu = io_buffer_virt(&hi3660->pmu_ssio);
31    writel(LDO3_ENABLE_BIT, iopmu + LDO3_ENABLE_REG);
32    return ZX_OK;
33}
34
35zx_status_t hi3660_init(zx_handle_t resource, zx_handle_t bti, hi3660_t** out) {
36    hi3660_t* hi3660 = calloc(1, sizeof(hi3660_t));
37    if (!hi3660) {
38        return ZX_ERR_NO_MEMORY;
39    }
40    list_initialize(&hi3660->gpios);
41
42    zx_status_t status;
43    if ((status = io_buffer_init_physical(&hi3660->usb3otg_bc, bti, MMIO_USB3OTG_BC_BASE,
44                                          MMIO_USB3OTG_BC_LENGTH, resource,
45                                          ZX_CACHE_POLICY_UNCACHED_DEVICE)) != ZX_OK ||
46         (status = io_buffer_init_physical(&hi3660->peri_crg, bti, MMIO_PERI_CRG_BASE,
47                                           MMIO_PERI_CRG_LENGTH, resource,
48                                           ZX_CACHE_POLICY_UNCACHED_DEVICE)) != ZX_OK ||
49         (status = io_buffer_init_physical(&hi3660->pctrl, bti, MMIO_PCTRL_BASE, MMIO_PCTRL_LENGTH,
50                                           resource, ZX_CACHE_POLICY_UNCACHED_DEVICE) != ZX_OK) ||
51         (status = io_buffer_init_physical(&hi3660->iomg_pmx4, bti, MMIO_IOMG_PMX4_BASE,
52                                           MMIO_IOMG_PMX4_LENGTH, resource,
53                                           ZX_CACHE_POLICY_UNCACHED_DEVICE)) != ZX_OK ||
54         (status = io_buffer_init_physical(&hi3660->pmu_ssio, bti, MMIO_PMU_SSI0_BASE,
55                                           MMIO_PMU_SSI0_LENGTH, resource,
56                                           ZX_CACHE_POLICY_UNCACHED_DEVICE)) != ZX_OK ||
57         (status = io_buffer_init_physical(&hi3660->iomcu, bti, MMIO_IOMCU_CONFIG_BASE,
58                                           MMIO_IOMCU_CONFIG_LENGTH, resource,
59                                           ZX_CACHE_POLICY_UNCACHED_DEVICE)) != ZX_OK) {
60        goto fail;
61    }
62
63    status = hi3660_gpio_init(hi3660, bti);
64    if (status != ZX_OK) {
65        goto fail;
66    }
67    status = hi3660_usb_init(hi3660);
68    if (status != ZX_OK) {
69        goto fail;
70    }
71
72    status = hi3660_i2c1_init(hi3660);
73    if (status != ZX_OK) {
74        goto fail;
75    }
76
77    status = hi3660_enable_ldo3(hi3660);
78    if (status != ZX_OK) {
79      goto fail;
80    }
81
82    status = hi3660_i2c_pinmux(hi3660);
83    if (status != ZX_OK) {
84        goto fail;
85    }
86
87    *out = hi3660;
88    return ZX_OK;
89
90fail:
91    zxlogf(ERROR, "hi3660_init failed %d\n", status);
92    hi3660_release(hi3660);
93    return status;
94}
95
96zx_status_t hi3660_get_protocol(hi3660_t* hi3660, uint32_t proto_id, void* out) {
97    switch (proto_id) {
98    case ZX_PROTOCOL_GPIO_IMPL:
99        memcpy(out, &hi3660->gpio, sizeof(hi3660->gpio));
100        return ZX_OK;
101    default:
102        return ZX_ERR_NOT_SUPPORTED;
103    }
104}
105
106void hi3660_release(hi3660_t* hi3660) {
107    hi3660_gpio_release(hi3660);
108    io_buffer_release(&hi3660->usb3otg_bc);
109    io_buffer_release(&hi3660->peri_crg);
110    io_buffer_release(&hi3660->pctrl);
111    free(hi3660);
112}
113