blob: be9623b870456c2d0365480b9a7ccb1df4251ed2 [file] [log] [blame]
// 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.
#ifndef SRC_DEVICES_LIB_AMLOGIC_INCLUDE_SOC_AML_COMMON_AML_PDM_AUDIO_H_
#define SRC_DEVICES_LIB_AMLOGIC_INCLUDE_SOC_AML_COMMON_AML_PDM_AUDIO_H_
#include <assert.h>
#include <lib/mmio/mmio.h>
#include <memory>
#include <utility>
#include <soc/aml-common/aml-audio-regs.h>
#include <soc/aml-common/aml-audio.h>
/*
Presently assumes stereo input with both streams multiplexed on the same
PDM input line. (TODO: support up to 8 channels to refactor gauss to use this)
*/
class AmlPdmDevice {
public:
DISALLOW_COPY_ASSIGN_AND_MOVE(AmlPdmDevice);
static std::unique_ptr<AmlPdmDevice> Create(
ddk::MmioBuffer pdm_mmio, ddk::MmioBuffer audio_mmio, ee_audio_mclk_src_t pdm_clk_src,
uint32_t sclk_div, uint32_t dclk_div, aml_toddr_t toddr_dev,
metadata::AmlVersion version = metadata::AmlVersion::kS905D2G);
// Sets the buffer/length pointers for dma engine
// must resize in lower 32-bits of address space
zx_status_t SetBuffer(zx_paddr_t buf, size_t len);
// Get HW alignment required in the buffer in bytes.
static uint32_t GetBufferAlignment() { return 8; }
/*
Returns offset of dma pointer in the ring buffer
*/
uint32_t GetRingPosition();
/*
Resets state of dma mechanisms and starts clocking data
in from pdm bus with data written to start of ring buffer
*/
uint64_t Start();
/*
Stops clocking stat in off PDM bus
(physical pdm bus signals remain active)
*/
void Stop();
/*
Synchronize the state of PDM bus signals with fifo/dma engine
*/
void Sync();
virtual void SetMute(uint8_t mute_mask);
/*
shuts down toddr, stops writing data to ring buffer
*/
void Shutdown();
uint32_t fifo_depth() const { return fifo_depth_; }
virtual void ConfigPdmIn(uint8_t mask);
void SetRate(uint32_t frames_per_second);
protected:
AmlPdmDevice(ddk::MmioBuffer pdm_mmio, ddk::MmioBuffer audio_mmio, ee_audio_mclk_src_t clk_src,
uint32_t sysclk_div, uint32_t dclk_div, aml_toddr_t toddr, uint32_t fifo_depth,
metadata::AmlVersion version)
: fifo_depth_(fifo_depth),
toddr_ch_(toddr),
clk_src_(clk_src),
sysclk_div_(sysclk_div),
dclk_div_(dclk_div),
toddr_base_(GetToddrBase(toddr)),
pdm_mmio_(std::move(pdm_mmio)),
audio_mmio_(std::move(audio_mmio)),
version_(version) {}
virtual ~AmlPdmDevice() = default;
private:
friend class std::default_delete<AmlPdmDevice>;
/* Get the register block offset for our ddr block */
static zx_off_t GetToddrBase(aml_toddr_t ch) {
switch (ch) {
case TODDR_A:
return EE_AUDIO_TODDR_A_CTRL0;
case TODDR_B:
return EE_AUDIO_TODDR_B_CTRL0;
case TODDR_C:
return EE_AUDIO_TODDR_C_CTRL0;
}
// We should never get here, but if we do, make it hard to ignore
ZX_PANIC("Invalid toddr channel specified!\n");
return 0;
}
void AudioClkEna(uint32_t audio_blk_mask);
void AudioClkDis(uint32_t audio_blk_mask);
void InitRegs();
void TODDREnable();
void TODDRDisable();
void PdmInDisable();
void PdmInEnable();
void ConfigFilters(uint32_t frames_per_second);
/* Get the register block offset for our ddr block */
zx_off_t GetToddrOffset(zx_off_t off) { return toddr_base_ + off; }
const uint32_t fifo_depth_; // in bytes.
const aml_toddr_t toddr_ch_; // fromddr channel used by this instance
const ee_audio_mclk_src_t clk_src_;
const uint32_t sysclk_div_;
const uint32_t dclk_div_;
const zx_off_t toddr_base_; // base offset of frddr ch used by this instance
const ddk::MmioBuffer pdm_mmio_;
const ddk::MmioBuffer audio_mmio_;
const metadata::AmlVersion version_;
};
#endif // SRC_DEVICES_LIB_AMLOGIC_INCLUDE_SOC_AML_COMMON_AML_PDM_AUDIO_H_