// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "audio-stream-in.h"

#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/driver.h>
#include <ddk/platform-defs.h>
#include <math.h>

#include <optional>
#include <utility>

namespace audio {
namespace sherlock {

// Expects 2 mics.
constexpr size_t kNumberOfChannels = 2;
// Calculate ring buffer size for 1 second of 16-bit, 48kHz.
constexpr size_t kRingBufferSize = fbl::round_up<size_t, size_t>(48000 * 2 * kNumberOfChannels,
                                                                 ZX_PAGE_SIZE);

SherlockAudioStreamIn::SherlockAudioStreamIn(zx_device_t* parent)
    : SimpleAudioStream(parent, true /* is input */) {
}

zx_status_t SherlockAudioStreamIn::Init() {
    zx_status_t status;

    status = InitPDev();
    if (status != ZX_OK) {
        return status;
    }

    status = AddFormats();
    if (status != ZX_OK) {
        return status;
    }
    // Set our gain capabilities.
    cur_gain_state_.cur_gain = 0;
    cur_gain_state_.cur_mute = false;
    cur_gain_state_.cur_agc = false;
    cur_gain_state_.min_gain = 0;
    cur_gain_state_.max_gain = 0;
    cur_gain_state_.gain_step = 0;
    cur_gain_state_.can_mute = false;
    cur_gain_state_.can_agc = false;

    snprintf(device_name_, sizeof(device_name_), "sherlock-audio-in");
    snprintf(mfr_name_, sizeof(mfr_name_), "unknown");
    snprintf(prod_name_, sizeof(prod_name_), "sherlock");

    unique_id_ = AUDIO_STREAM_UNIQUE_ID_BUILTIN_MICROPHONE;

    return ZX_OK;
}

zx_status_t SherlockAudioStreamIn::InitPDev() {
    pdev_protocol_t pdev;
    zx_status_t status = device_get_protocol(parent(), ZX_PROTOCOL_PDEV, &pdev);
    if (status) {
        return status;
    }
    pdev_ = ddk::PDev(&pdev);

    status = pdev_->GetBti(0, &bti_);
    if (status != ZX_OK) {
        zxlogf(ERROR, "%s could not obtain bti - %d\n", __func__, status);
        return status;
    }
    std::optional<ddk::MmioBuffer> mmio0, mmio1;
    status = pdev_->MapMmio(0, &mmio0);
    if (status != ZX_OK) {
        return status;
    }
    status = pdev_->MapMmio(1, &mmio1);
    if (status != ZX_OK) {
        return status;
    }

    pdm_ = AmlPdmDevice::Create(*std::move(mmio0),
                                *std::move(mmio1),
                                HIFI_PLL,
                                7,   // clk_div for mclk = T931_HIFI_PLL_RATE/clk_div = 219.43 MHz.
                                499, // clk_div for pdm_dclk = T931_HIFI_PLL_RATE/clk_div = 3.07MHz.
                                TODDR_B);
    if (pdm_ == nullptr) {
        zxlogf(ERROR, "%s failed to create pdm device\n", __func__);
        return ZX_ERR_NO_MEMORY;
    }

    InitBuffer(kRingBufferSize);

    pdm_->SetBuffer(pinned_ring_buffer_.region(0).phys_addr,
                    pinned_ring_buffer_.region(0).size);

    pdm_->ConfigPdmIn((1 << kNumberOfChannels) - 1); // First kNumberOfChannels channels.

    pdm_->Sync();

    return ZX_OK;
}

zx_status_t SherlockAudioStreamIn::ChangeFormat(const audio_proto::StreamSetFmtReq& req) {
    fifo_depth_ = pdm_->fifo_depth();
    external_delay_nsec_ = 0;

    // At this time only one format is supported, and hardware is initialized
    //  during driver binding, so nothing to do at this time.
    return ZX_OK;
}

zx_status_t SherlockAudioStreamIn::GetBuffer(const audio_proto::RingBufGetBufferReq& req,
                                             uint32_t* out_num_rb_frames,
                                             zx::vmo* out_buffer) {
    uint32_t rb_frames =
        static_cast<uint32_t>(pinned_ring_buffer_.region(0).size) / frame_size_;

    if (req.min_ring_buffer_frames > rb_frames) {
        return ZX_ERR_OUT_OF_RANGE;
    }
    zx_status_t status;
    constexpr uint32_t rights = ZX_RIGHT_READ | ZX_RIGHT_WRITE | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER;
    status = ring_buffer_vmo_.duplicate(rights, out_buffer);
    if (status != ZX_OK) {
        return status;
    }

    *out_num_rb_frames = rb_frames;

    pdm_->SetBuffer(pinned_ring_buffer_.region(0).phys_addr,
                    rb_frames * frame_size_);
    return ZX_OK;
}

zx_status_t SherlockAudioStreamIn::Start(uint64_t* out_start_time) {
    *out_start_time = pdm_->Start();

    uint32_t notifs = LoadNotificationsPerRing();
    if (notifs) {
        us_per_notification_ = static_cast<uint32_t>(
            1000 * pinned_ring_buffer_.region(0).size / (frame_size_ * 48 * notifs));
        notify_timer_->Arm(zx_deadline_after(ZX_USEC(us_per_notification_)));
    } else {
        us_per_notification_ = 0;
    }
    return ZX_OK;
}

// Timer handler for sending out position notifications.
zx_status_t SherlockAudioStreamIn::ProcessRingNotification() {
    ZX_ASSERT(us_per_notification_ != 0);

    notify_timer_->Arm(zx_deadline_after(ZX_USEC(us_per_notification_)));

    audio_proto::RingBufPositionNotify resp = {};
    resp.hdr.cmd = AUDIO_RB_POSITION_NOTIFY;

    resp.ring_buffer_pos = pdm_->GetRingPosition();
    return NotifyPosition(resp);
}

zx_status_t SherlockAudioStreamIn::InitPost() {

    notify_timer_ = dispatcher::Timer::Create();
    if (notify_timer_ == nullptr) {
        return ZX_ERR_NO_MEMORY;
    }

    dispatcher::Timer::ProcessHandler thandler(
        [pdm = this](dispatcher::Timer * timer)->zx_status_t {
            OBTAIN_EXECUTION_DOMAIN_TOKEN(t, pdm->domain_);
            return pdm->ProcessRingNotification();
        });

    return notify_timer_->Activate(domain_, std::move(thandler));
}

zx_status_t SherlockAudioStreamIn::Stop() {
    notify_timer_->Cancel();
    us_per_notification_ = 0;
    pdm_->Stop();
    return ZX_OK;
}

zx_status_t SherlockAudioStreamIn::AddFormats() {
    fbl::AllocChecker ac;
    supported_formats_.reserve(1, &ac);
    if (!ac.check()) {
        zxlogf(ERROR, "Out of memory, can not create supported formats list\n");
        return ZX_ERR_NO_MEMORY;
    }

    audio_stream_format_range_t range;
    range.min_channels = kNumberOfChannels;
    range.max_channels = kNumberOfChannels;
    range.sample_formats = AUDIO_SAMPLE_FORMAT_16BIT;
    range.min_frames_per_second = 48000;
    range.max_frames_per_second = 48000;
    range.flags = ASF_RANGE_FLAG_FPS_48000_FAMILY;

    supported_formats_.push_back(range);

    return ZX_OK;
}

zx_status_t SherlockAudioStreamIn::InitBuffer(size_t size) {
    // TODO(ZX-3149): Per johngro's suggestion preallocate contiguous memory (say in
    // platform bus) since we are likely to fail after running for a while and we need to
    // init again (say the devhost is restarted).
    zx_status_t status = zx_vmo_create_contiguous(bti_.get(), size, 0,
                                                  ring_buffer_vmo_.reset_and_get_address());
    if (status != ZX_OK) {
        zxlogf(ERROR, "%s failed to allocate ring buffer vmo - %d\n", __func__, status);
        return status;
    }

    status = pinned_ring_buffer_.Pin(ring_buffer_vmo_, bti_, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE);
    if (status != ZX_OK) {
        zxlogf(ERROR, "%s failed to pin ring buffer vmo - %d\n", __func__, status);
        return status;
    }
    if (pinned_ring_buffer_.region_count() != 1) {
        zxlogf(ERROR, "%s buffer is not contiguous", __func__);
        return ZX_ERR_NO_MEMORY;
    }

    return ZX_OK;
}

} //namespace sherlock
} //namespace audio

extern "C" zx_status_t pdm_audio_bind(void* ctx, zx_device_t* parent) {

    auto stream =
        audio::SimpleAudioStream::Create<audio::sherlock::SherlockAudioStreamIn>(parent);
    if (stream == nullptr) {
        return ZX_ERR_NO_MEMORY;
    }

    return ZX_OK;
}
