blob: 9ac95f21e070310e7c1fd3410e10c010d73809c3 [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.
#include <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h>
#include <lib/ddk/binding.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/metadata.h>
#include <lib/ddk/platform-defs.h>
#include <lib/driver/component/cpp/composite_node_spec.h>
#include <lib/driver/component/cpp/node_add_args.h>
#include <string.h>
#include <bind/fuchsia/amlogic/platform/cpp/bind.h>
#include <bind/fuchsia/clock/cpp/bind.h>
#include <bind/fuchsia/cpp/bind.h>
#include <bind/fuchsia/gpio/cpp/bind.h>
#include <bind/fuchsia/hardware/audio/cpp/bind.h>
#include <bind/fuchsia/hardware/gpio/cpp/bind.h>
#include <bind/fuchsia/hardware/i2c/cpp/bind.h>
#include <bind/fuchsia/ti/platform/cpp/bind.h>
#include <soc/aml-common/aml-audio.h>
#include <soc/aml-meson/g12b-clk.h>
#include <soc/aml-t931/t931-gpio.h>
#include <soc/aml-t931/t931-hw.h>
#include <ti/ti-audio.h>
#include "sherlock-gpios.h"
#include "sherlock.h"
// Enables BT PCM audio.
#define ENABLE_BT
namespace fdf {
using namespace fuchsia_driver_framework;
} // namespace fdf
namespace sherlock {
namespace fpbus = fuchsia_hardware_platform_bus;
zx_status_t AddTas5720Device(fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus>& pbus,
const char* device_name, uint32_t device_instance_id,
uint32_t i2c_address, const uint32_t* instance_count) {
fpbus::Node dev;
dev.name() = device_name;
dev.pid() = PDEV_PID_GENERIC;
dev.vid() = PDEV_VID_TI;
dev.did() = PDEV_DID_TI_TAS5720;
dev.instance_id() = device_instance_id;
dev.metadata() = std::vector<fpbus::Metadata>{
{{
.type = DEVICE_METADATA_PRIVATE,
.data = std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(instance_count),
reinterpret_cast<const uint8_t*>(instance_count) + sizeof(*instance_count)),
}},
};
const auto gpio_init_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia::INIT_STEP, bind_fuchsia_gpio::BIND_INIT_STEP_GPIO),
};
const auto gpio_init_props = std::vector{
fdf::MakeProperty(bind_fuchsia::INIT_STEP, bind_fuchsia_gpio::BIND_INIT_STEP_GPIO),
};
const auto i2c_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID, static_cast<uint32_t>(SHERLOCK_I2C_A0_0)),
fdf::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS, i2c_address),
};
const auto i2c_props = std::vector{
fdf::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
};
std::vector<fuchsia_driver_framework::ParentSpec> parents = {
fuchsia_driver_framework::ParentSpec{{
.bind_rules = std::move(gpio_init_rules),
.properties = std::move(gpio_init_props),
}},
fuchsia_driver_framework::ParentSpec{{
.bind_rules = std::move(i2c_rules),
.properties = std::move(i2c_props),
}}};
fidl::Arena<> fidl_arena;
fdf::Arena arena('5720');
auto result = pbus.buffer(arena)->AddCompositeNodeSpec(
fidl::ToWire(fidl_arena, dev),
fidl::ToWire(fidl_arena, fuchsia_driver_framework::CompositeNodeSpec{
{.name = device_name, .parents = parents}}));
if (!result.ok()) {
zxlogf(ERROR, "Failed to send AddComposite request: %s", result.status_string());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "Failed to add composite: %s", zx_status_get_string(result->error_value()));
return result->error_value();
}
return ZX_OK;
}
zx_status_t Sherlock::AudioInit() {
using fuchsia_hardware_clockimpl::wire::InitCall;
uint8_t tdm_instance_id = 1;
static const std::vector<fpbus::Mmio> audio_mmios{
{{
.base = T931_EE_AUDIO_BASE,
.length = T931_EE_AUDIO_LENGTH,
}},
{{
.base = T931_GPIO_BASE,
.length = T931_GPIO_LENGTH,
}},
{{
.base = T931_GPIO_AO_BASE,
.length = T931_GPIO_AO_LENGTH,
}},
};
static const std::vector<fpbus::Bti> tdm_btis{
{{
.iommu_index = 0,
.bti_id = BTI_AUDIO_OUT,
}},
};
static const std::vector<fpbus::Irq> frddr_b_irqs{
{{
.irq = T931_AUDIO_FRDDR_B,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
}},
};
static const std::vector<fpbus::Irq> toddr_b_irqs{
{{
.irq = T931_AUDIO_TODDR_B,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
}},
};
fidl::Arena<> fidl_arena;
fdf::Arena arena('AUDI');
const char* product_name = "sherlock";
constexpr size_t device_name_max_length = 32;
std::vector<fdf::ParentSpec> sherlock_tdm_i2s_parents;
sherlock_tdm_i2s_parents.reserve(6);
const auto gpio_init_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia::INIT_STEP, bind_fuchsia_gpio::BIND_INIT_STEP_GPIO),
};
const auto gpio_init_props = std::vector{
fdf::MakeProperty(bind_fuchsia::INIT_STEP, bind_fuchsia_gpio::BIND_INIT_STEP_GPIO),
};
const auto clock_init_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia::INIT_STEP, bind_fuchsia_clock::BIND_INIT_STEP_CLOCK),
};
const auto clock_init_props = std::vector{
fdf::MakeProperty(bind_fuchsia::INIT_STEP, bind_fuchsia_clock::BIND_INIT_STEP_CLOCK),
};
const auto init_parents = std::vector{
fdf::ParentSpec{{gpio_init_rules, gpio_init_props}},
fdf::ParentSpec{{clock_init_rules, clock_init_props}},
};
sherlock_tdm_i2s_parents.insert(sherlock_tdm_i2s_parents.end(), init_parents.begin(),
init_parents.end());
// Add a spec for the enable audio GPIO pin.
auto enable_audio_gpio_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::GPIO_PIN, static_cast<uint32_t>(GPIO_SOC_AUDIO_EN)),
};
auto enable_audio_gpio_props = std::vector{
fdf::MakeProperty(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia_gpio::FUNCTION, bind_fuchsia_gpio::FUNCTION_SOC_AUDIO_ENABLE),
};
sherlock_tdm_i2s_parents.push_back(fdf::ParentSpec{{
.bind_rules = enable_audio_gpio_rules,
.properties = enable_audio_gpio_props,
}});
// Add a composite for each codec instance.
for (size_t i = 0; i < 3; i++) {
auto codec_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_audio::CODECSERVICE,
bind_fuchsia_hardware_audio::CODECSERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::PLATFORM_DEV_VID,
bind_fuchsia_ti_platform::BIND_PLATFORM_DEV_VID_TI),
fdf::MakeAcceptBindRule(bind_fuchsia::PLATFORM_DEV_DID,
bind_fuchsia_ti_platform::BIND_PLATFORM_DEV_DID_TAS5720),
fdf::MakeAcceptBindRule(bind_fuchsia::CODEC_INSTANCE, static_cast<uint32_t>(i + 1)),
};
auto codec_props = std::vector{
fdf::MakeProperty(bind_fuchsia_hardware_audio::CODECSERVICE,
bind_fuchsia_hardware_audio::CODECSERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia::CODEC_INSTANCE, static_cast<uint32_t>(i + 1)),
};
sherlock_tdm_i2s_parents.push_back(fdf::ParentSpec{{
.bind_rules = codec_rules,
.properties = codec_props,
}});
}
clock_init_steps_.push_back({g12b_clk::CLK_HIFI_PLL, InitCall::WithDisable({})});
clock_init_steps_.push_back(
{g12b_clk::CLK_HIFI_PLL, InitCall::WithRateHz(init_arena_, T931_HIFI_PLL_RATE)});
clock_init_steps_.push_back({g12b_clk::CLK_HIFI_PLL, InitCall::WithEnable({})});
// TDM pin configuration.
gpio_init_steps_.push_back({T931_GPIOZ(7), GpioSetAltFunction(T931_GPIOZ_7_TDMC_SCLK_FN)});
gpio_init_steps_.push_back({T931_GPIOZ(6), GpioSetAltFunction(T931_GPIOZ_6_TDMC_FS_FN)});
gpio_init_steps_.push_back({T931_GPIOZ(2), GpioSetAltFunction(T931_GPIOZ_2_TDMC_D0_FN)});
constexpr uint64_t ua = 3000;
gpio_init_steps_.push_back({T931_GPIOZ(7), GpioSetDriveStrength(ua)});
gpio_init_steps_.push_back({T931_GPIOZ(6), GpioSetDriveStrength(ua)});
gpio_init_steps_.push_back({T931_GPIOZ(2), GpioSetDriveStrength(ua)});
gpio_init_steps_.push_back({T931_GPIOZ(3), GpioSetAltFunction(T931_GPIOZ_3_TDMC_D1_FN)});
gpio_init_steps_.push_back({T931_GPIOZ(3), GpioSetDriveStrength(ua)});
gpio_init_steps_.push_back({T931_GPIOAO(9), GpioSetAltFunction(T931_GPIOAO_9_MCLK_FN)});
gpio_init_steps_.push_back({T931_GPIOAO(9), GpioSetDriveStrength(ua)});
#ifdef ENABLE_BT
// PCM pin assignments.
gpio_init_steps_.push_back({T931_GPIOX(8), GpioSetAltFunction(T931_GPIOX_8_TDMA_DIN1_FN)});
gpio_init_steps_.push_back({T931_GPIOX(9), GpioSetAltFunction(T931_GPIOX_9_TDMA_D0_FN)});
gpio_init_steps_.push_back({T931_GPIOX(10), GpioSetAltFunction(T931_GPIOX_10_TDMA_FS_FN)});
gpio_init_steps_.push_back({T931_GPIOX(11), GpioSetAltFunction(T931_GPIOX_11_TDMA_SCLK_FN)});
gpio_init_steps_.push_back({T931_GPIOX(9), GpioSetDriveStrength(ua)});
gpio_init_steps_.push_back({T931_GPIOX(10), GpioSetDriveStrength(ua)});
gpio_init_steps_.push_back({T931_GPIOX(11), GpioSetDriveStrength(ua)});
#endif
// PDM pin assignments.
gpio_init_steps_.push_back({T931_GPIOA(7), GpioSetAltFunction(T931_GPIOA_7_PDM_DCLK_FN)});
gpio_init_steps_.push_back({T931_GPIOA(8), GpioSetAltFunction(T931_GPIOA_8_PDM_DIN0_FN)});
// Add TDM OUT to the codecs.
{
gpio_init_steps_.push_back({T931_GPIOH(7), GpioConfigOut(1)}); // SOC_AUDIO_EN.
constexpr uint32_t woofer_instance_count = 1;
zx_status_t status = AddTas5720Device(pbus_, "audio-tas5720-woofer", woofer_instance_count,
0x6f, &woofer_instance_count);
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to add woofer composite device: %s", zx_status_get_string(status));
return status;
}
constexpr uint32_t left_tweeter_instance_count = 2;
status = AddTas5720Device(pbus_, "audio-tas5720-left-tweeter", left_tweeter_instance_count,
0x6c, &left_tweeter_instance_count);
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to add left tweeter composite device: %s",
zx_status_get_string(status));
return status;
}
constexpr uint32_t right_tweeter_instance_count = 3;
status = AddTas5720Device(pbus_, "audio-tas5720-right-tweeter", right_tweeter_instance_count,
0x6d, &right_tweeter_instance_count);
if (status != ZX_OK) {
zxlogf(ERROR, "Failed to add right tweeter composite device: %s",
zx_status_get_string(status));
return status;
}
}
metadata::AmlConfig metadata = {};
snprintf(metadata.manufacturer, sizeof(metadata.manufacturer), "Spacely Sprockets");
strncpy(metadata.product_name, product_name, sizeof(metadata.product_name));
metadata.is_input = false;
// Compatible clocks with other TDM drivers.
metadata.mClockDivFactor = 10;
metadata.sClockDivFactor = 25;
metadata.unique_id = AUDIO_STREAM_UNIQUE_ID_BUILTIN_SPEAKERS;
metadata.bus = metadata::AmlBus::TDM_C;
metadata.version = metadata::AmlVersion::kS905D2G; // Also works with T931G.
metadata.dai.type = metadata::DaiType::I2s;
metadata.dai.bits_per_sample = 16;
metadata.dai.bits_per_slot = 32;
// Ranges could be wider, but only using them crossed-over at 1'200 Hz in this product.
metadata.ring_buffer.frequency_ranges[0].min_frequency = 20;
metadata.ring_buffer.frequency_ranges[0].max_frequency = 1'600;
metadata.ring_buffer.frequency_ranges[1].min_frequency = 20;
metadata.ring_buffer.frequency_ranges[1].max_frequency = 1'600;
metadata.ring_buffer.frequency_ranges[2].min_frequency = 1'000;
metadata.ring_buffer.frequency_ranges[2].max_frequency = 40'000;
metadata.ring_buffer.frequency_ranges[3].min_frequency = 1'000;
metadata.ring_buffer.frequency_ranges[3].max_frequency = 40'000;
metadata.codecs.number_of_codecs = 3;
metadata.codecs.types[0] = metadata::CodecType::Tas5720;
metadata.codecs.types[1] = metadata::CodecType::Tas5720;
metadata.codecs.types[2] = metadata::CodecType::Tas5720;
// This driver advertises 4 channels.
// The samples in the first channel are unused (can be zero).
// The samples in the second channel are used for the woofer and are expected to have a mix of
// both left and right channel from stereo audio.
// The samples in the third channel are expected to come from the left channel of stereo audio
// and are used for the left tweeter.
// The samples in the fourth channel are expected to come from the right channel of stereo audio
// and are used for the right tweeter.
metadata.ring_buffer.number_of_channels = 4;
metadata.swaps = 0x0123;
metadata.lanes_enable_mask[0] = 3;
metadata.lanes_enable_mask[1] = 3;
#ifndef FACTORY_BUILD
// Delta between woofers and tweeters of 6.4dB.
metadata.codecs.delta_gains[0] = 0.f;
metadata.codecs.delta_gains[1] = -6.4f;
metadata.codecs.delta_gains[2] = -6.4f;
#endif // FACTORY_BUILD
metadata.codecs.channels_to_use_bitmask[0] = 0x2; // Woofer uses DAI right I2S channel.
metadata.codecs.channels_to_use_bitmask[1] = 0x1; // L tweeter uses DAI left I2S channel.
metadata.codecs.channels_to_use_bitmask[2] = 0x2; // R tweeter uses DAI right I2S channel.
// The woofer samples are expected in the second position out of four channels.
// In a 4-bit bitmask, counting from least-significant bit, this is index 1: value 2^1 = 2.
metadata.codecs.ring_buffer_channels_to_use_bitmask[0] = 0x2; // Woofer uses index 1.
metadata.codecs.ring_buffer_channels_to_use_bitmask[1] = 0x4; // L tweeter uses index 2.
metadata.codecs.ring_buffer_channels_to_use_bitmask[2] = 0x8; // R tweeter uses index 3.
std::vector<fpbus::Metadata> tdm_metadata{
{{
.type = DEVICE_METADATA_PRIVATE,
.data =
std::vector<uint8_t>(reinterpret_cast<const uint8_t*>(&metadata),
reinterpret_cast<const uint8_t*>(&metadata) + sizeof(metadata)),
}},
};
fpbus::Node tdm_dev;
char name[device_name_max_length];
snprintf(name, sizeof(name), "%s-i2s-audio-out", product_name);
tdm_dev.name() = name;
tdm_dev.vid() = bind_fuchsia_amlogic_platform::BIND_PLATFORM_DEV_VID_AMLOGIC;
tdm_dev.pid() = bind_fuchsia_amlogic_platform::BIND_PLATFORM_DEV_PID_T931;
tdm_dev.did() = bind_fuchsia_amlogic_platform::BIND_PLATFORM_DEV_DID_TDM;
tdm_dev.instance_id() = tdm_instance_id++;
tdm_dev.mmio() = audio_mmios;
tdm_dev.bti() = tdm_btis;
tdm_dev.irq() = frddr_b_irqs;
tdm_dev.metadata() = tdm_metadata;
{
fidl::Arena<> fidl_arena;
fdf::Arena arena('AUDI');
auto sherlock_tdm_i2s_spec = fdf::CompositeNodeSpec{{
.name = "aml_tdm",
.parents = sherlock_tdm_i2s_parents,
}};
auto result = pbus_.buffer(arena)->AddCompositeNodeSpec(
fidl::ToWire(fidl_arena, tdm_dev), fidl::ToWire(fidl_arena, sherlock_tdm_i2s_spec));
if (!result.ok()) {
zxlogf(ERROR, "AddCompositeNodeSpec Audio(tdm_dev) request failed: %s",
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "AddCompositeNodeSpec Audio(tdm_dev) failed: %s",
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
#ifdef ENABLE_BT
// Add TDM OUT for BT.
{
static const std::vector<fpbus::Bti> pcm_out_btis{
{{
.iommu_index = 0,
.bti_id = BTI_AUDIO_BT_OUT,
}},
};
metadata::AmlConfig metadata = {};
snprintf(metadata.manufacturer, sizeof(metadata.manufacturer), "Spacely Sprockets");
strncpy(metadata.product_name, product_name, sizeof(metadata.product_name));
metadata.is_input = false;
// Compatible clocks with other TDM drivers.
metadata.mClockDivFactor = 10;
metadata.sClockDivFactor = 25;
metadata.unique_id = AUDIO_STREAM_UNIQUE_ID_BUILTIN_BT;
metadata.bus = metadata::AmlBus::TDM_A;
metadata.version = metadata::AmlVersion::kS905D2G;
metadata.dai.type = metadata::DaiType::Tdm1;
metadata.dai.sclk_on_raising = true;
metadata.dai.bits_per_sample = 16;
metadata.dai.bits_per_slot = 16;
metadata.ring_buffer.number_of_channels = 1;
metadata.dai.number_of_channels = 1;
metadata.lanes_enable_mask[0] = 1;
std::vector<fpbus::Metadata> tdm_metadata{
{{
.type = DEVICE_METADATA_PRIVATE,
.data = std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(&metadata),
reinterpret_cast<const uint8_t*>(&metadata) + sizeof(metadata)),
}},
};
fpbus::Node tdm_dev;
char tdm_name[device_name_max_length];
snprintf(tdm_name, sizeof(tdm_name), "%s-pcm-dai-out", product_name);
tdm_dev.name() = tdm_name;
tdm_dev.vid() = PDEV_VID_AMLOGIC;
tdm_dev.pid() = PDEV_PID_AMLOGIC_T931;
tdm_dev.did() = PDEV_DID_AMLOGIC_DAI_OUT;
tdm_dev.instance_id() = tdm_instance_id++;
tdm_dev.mmio() = audio_mmios;
tdm_dev.bti() = pcm_out_btis;
tdm_dev.metadata() = tdm_metadata;
{
auto tdm_spec = fdf::CompositeNodeSpec{{
"aml_tdm_dai_out",
init_parents,
}};
auto result = pbus_.buffer(arena)->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, tdm_dev),
fidl::ToWire(fidl_arena, tdm_spec));
if (!result.ok()) {
zxlogf(ERROR, "AddCompositeNodeSpec(tdm_dev) request failed: %s",
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "AddCompositeNodeSpec(tdm_dev) failed: %s",
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
}
#endif
// Input device.
{
metadata::AmlPdmConfig metadata = {};
snprintf(metadata.manufacturer, sizeof(metadata.manufacturer), "Spacely Sprockets");
snprintf(metadata.product_name, sizeof(metadata.product_name), "sherlock");
metadata.number_of_channels = 2;
metadata.version = metadata::AmlVersion::kS905D2G;
metadata.sysClockDivFactor = 4;
metadata.dClockDivFactor = 250;
std::vector<fpbus::Metadata> pdm_metadata{
{{
.type = DEVICE_METADATA_PRIVATE,
.data = std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(&metadata),
reinterpret_cast<const uint8_t*>(&metadata) + sizeof(metadata)),
}},
};
static const std::vector<fpbus::Mmio> pdm_mmios{
{{
.base = T931_EE_PDM_BASE,
.length = T931_EE_PDM_LENGTH,
}},
{{
.base = T931_EE_AUDIO_BASE,
.length = T931_EE_AUDIO_LENGTH,
}},
};
static const std::vector<fpbus::Bti> pdm_btis{
{{
.iommu_index = 0,
.bti_id = BTI_AUDIO_IN,
}},
};
fpbus::Node dev_in;
char pdm_name[device_name_max_length];
snprintf(pdm_name, sizeof(pdm_name), "%s-pdm-audio-in", product_name);
dev_in.name() = pdm_name;
dev_in.vid() = PDEV_VID_AMLOGIC;
dev_in.pid() = PDEV_PID_AMLOGIC_T931;
dev_in.did() = PDEV_DID_AMLOGIC_PDM;
dev_in.mmio() = pdm_mmios;
dev_in.bti() = pdm_btis;
dev_in.irq() = toddr_b_irqs;
dev_in.metadata() = pdm_metadata;
{
auto pdm_spec = fdf::CompositeNodeSpec{{
"aml_pdm",
init_parents,
}};
auto result = pbus_.buffer(arena)->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, dev_in),
fidl::ToWire(fidl_arena, pdm_spec));
if (!result.ok()) {
zxlogf(ERROR, "AddCompositeNodeSpec Audio(dev_in) request failed: %s",
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "AddCompositeNodeSpec Audio(dev_in) failed: %s",
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
}
#ifdef ENABLE_BT
// Add TDM IN for BT.
{
static const std::vector<fpbus::Bti> pcm_in_btis{
{{
.iommu_index = 0,
.bti_id = BTI_AUDIO_BT_IN,
}},
};
metadata::AmlConfig metadata = {};
snprintf(metadata.manufacturer, sizeof(metadata.manufacturer), "Spacely Sprockets");
strncpy(metadata.product_name, product_name, sizeof(metadata.product_name));
metadata.is_input = true;
// Compatible clocks with other TDM drivers.
metadata.mClockDivFactor = 10;
metadata.sClockDivFactor = 25;
metadata.unique_id = AUDIO_STREAM_UNIQUE_ID_BUILTIN_BT;
metadata.bus = metadata::AmlBus::TDM_A;
metadata.version = metadata::AmlVersion::kS905D2G;
metadata.dai.type = metadata::DaiType::Tdm1;
metadata.dai.sclk_on_raising = true;
metadata.dai.bits_per_sample = 16;
metadata.dai.bits_per_slot = 16;
metadata.ring_buffer.number_of_channels = 1;
metadata.dai.number_of_channels = 1;
metadata.swaps = 0x0200;
metadata.lanes_enable_mask[1] = 1;
std::vector<fpbus::Metadata> tdm_metadata{
{{
.type = DEVICE_METADATA_PRIVATE,
.data = std::vector<uint8_t>(
reinterpret_cast<const uint8_t*>(&metadata),
reinterpret_cast<const uint8_t*>(&metadata) + sizeof(metadata)),
}},
};
fpbus::Node tdm_dev;
char name[device_name_max_length];
snprintf(name, sizeof(name), "%s-pcm-dai-in", product_name);
tdm_dev.name() = name;
tdm_dev.vid() = PDEV_VID_AMLOGIC;
tdm_dev.pid() = PDEV_PID_AMLOGIC_T931;
tdm_dev.did() = PDEV_DID_AMLOGIC_DAI_IN;
tdm_dev.instance_id() = tdm_instance_id++;
tdm_dev.mmio() = audio_mmios;
tdm_dev.bti() = pcm_in_btis;
tdm_dev.metadata() = tdm_metadata;
{
auto tdm_spec = fdf::CompositeNodeSpec{{
"aml_tdm_dai_in",
init_parents,
}};
auto result = pbus_.buffer(arena)->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, tdm_dev),
fidl::ToWire(fidl_arena, tdm_spec));
if (!result.ok()) {
zxlogf(ERROR, "AddCompositeNodeSpec(tdm_dev) request failed: %s",
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "AddCompositeNodeSpec(tdm_dev) failed: %s",
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
}
#endif
return ZX_OK;
}
} // namespace sherlock