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 "hikey-usb.h"
6
7#include <assert.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.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/gpio.h>
18#include <ddk/protocol/platform-defs.h>
19#include <ddk/protocol/platform-device.h>
20#include <fbl/algorithm.h>
21#include <fbl/unique_ptr.h>
22
23namespace hikey_usb {
24
25zx_status_t HikeyUsb::Create(zx_device_t* parent) {
26    fbl::AllocChecker ac;
27    auto bus = fbl::make_unique_checked<HikeyUsb>(&ac, parent);
28    if (!ac.check()) {
29        return ZX_ERR_NO_MEMORY;
30    }
31
32    auto status = bus->Init();
33    if (status != ZX_OK) {
34        return status;
35    }
36
37    // devmgr is now in charge of the device.
38    __UNUSED auto* dummy = bus.release();
39    return ZX_OK;
40}
41
42zx_status_t HikeyUsb::Init() {
43    platform_device_protocol_t pdev;
44
45    auto status = device_get_protocol(parent(), ZX_PROTOCOL_PLATFORM_DEV, &pdev);
46    if (status != ZX_OK) {
47        return status;
48    }
49    for (uint32_t i = 0; i < countof(gpios_); i++) {
50        status = pdev_get_protocol(&pdev, ZX_PROTOCOL_GPIO, i, &gpios_[i]);
51        if (status != ZX_OK) {
52            return status;
53        }
54        gpio_config_out(&gpios_[i], 0);
55    }
56
57    zx_device_prop_t props[] = {
58        {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_GENERIC},
59        {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_GENERIC},
60        {BIND_PLATFORM_DEV_DID, 0, PDEV_DID_USB_DWC3},
61    };
62
63    device_add_args_t args = {};
64    args.version = DEVICE_ADD_ARGS_VERSION;
65    args.name = "dwc3";
66    args.ctx = this;
67    args.ops = &ddk_device_proto_;
68    args.props = props;
69    args.prop_count = static_cast<uint32_t>(fbl::count_of(props));
70    args.proto_id = ddk_proto_id_;
71    args.proto_ops = ddk_proto_ops_;
72
73    return pdev_device_add(&pdev, 0, &args, &zxdev_);
74}
75
76zx_status_t HikeyUsb::UmsSetMode(usb_mode_t mode) {
77    if (mode == usb_mode_) {
78        return ZX_OK;
79    }
80    if (mode == USB_MODE_OTG) {
81        return ZX_ERR_NOT_SUPPORTED;
82    }
83
84    gpio_write(&gpios_[HUB_VDD33_EN], mode == USB_MODE_HOST);
85    gpio_write(&gpios_[VBUS_TYPEC], mode == USB_MODE_HOST);
86    gpio_write(&gpios_[USBSW_SW_SEL], mode == USB_MODE_HOST);
87
88    usb_mode_ = mode;
89    return ZX_OK;
90
91
92    return ZX_OK;
93}
94
95void HikeyUsb::DdkRelease() {
96    delete this;
97}
98
99} // namespace hikey_usb
100
101zx_status_t hikey_usb_bind(void* ctx, zx_device_t* parent) {
102    return hikey_usb::HikeyUsb::Create(parent);
103}
104