blob: 281727006b5c83a390549aadcaf018d141fb3c13 [file] [log] [blame]
// Copyright 2019 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 "max98373.h"
#include <fuchsia/hardware/gpio/cpp/banjo-mock.h>
#include <lib/fake_ddk/fake_ddk.h>
#include <lib/mock-i2c/mock-i2c.h>
#include <lib/simple-codec/simple-codec-client.h>
#include <lib/simple-codec/simple-codec-helper.h>
#include <zxtest/zxtest.h>
namespace audio {
struct Max98373Codec : public Max98373 {
explicit Max98373Codec(const ddk::I2cChannel& i2c, const ddk::GpioProtocolClient& codec_reset)
: Max98373(fake_ddk::kFakeParent, i2c, codec_reset) {}
codec_protocol_t GetProto() { return {&this->codec_protocol_ops_, this}; }
};
TEST(Max98373Test, GetInfo) {
fake_ddk::Bind tester;
mock_i2c::MockI2c unused_i2c;
ddk::GpioProtocolClient unused_gpio;
auto codec =
SimpleCodecServer::Create<Max98373Codec>(unused_i2c.GetProto(), std::move(unused_gpio));
ASSERT_NOT_NULL(codec);
auto codec_proto = codec->GetProto();
SimpleCodecClient client;
client.SetProtocol(&codec_proto);
{
auto info = client.GetInfo();
EXPECT_EQ(info.value().unique_id.compare(""), 0);
EXPECT_EQ(info.value().manufacturer.compare("Maxim"), 0);
EXPECT_EQ(info.value().product_name.compare("MAX98373"), 0);
}
codec->DdkAsyncRemove();
ASSERT_TRUE(tester.Ok());
codec.release()->DdkRelease(); // codec release managed by the DDK
}
TEST(Max98373Test, Reset) {
fake_ddk::Bind tester;
mock_i2c::MockI2c mock_i2c;
mock_i2c
.ExpectWriteStop({0x20, 0x00, 0x01}, ZX_ERR_INTERNAL) // Reset, error will retry.
.ExpectWriteStop({0x20, 0x00, 0x01}, ZX_ERR_INTERNAL) // Reset, error will retry.
.ExpectWriteStop({0x20, 0x00, 0x01}) // Reset.
.ExpectWrite({0x21, 0xff})
.ExpectReadStop({0x43}) // Get revision id.
.ExpectWriteStop({0x20, 0xff, 0x01}) // Global enable.
.ExpectWriteStop({0x20, 0x43, 0x01}) // Speaker enable.
.ExpectWriteStop({0x20, 0x3d, 0x28}) // Set gain to -20dB.
.ExpectWriteStop({0x20, 0x2b, 0x01}) // Data in enable.
.ExpectWriteStop({0x20, 0x24, 0xc0}) // I2S.
.ExpectWriteStop({0x20, 0x27, 0x08}); // 48KHz.
ddk::MockGpio mock_gpio;
mock_gpio.ExpectWrite(ZX_OK, 0).ExpectWrite(ZX_OK, 1); // Reset, set to 0 and then to 1.
ddk::GpioProtocolClient gpio(mock_gpio.GetProto());
auto codec = SimpleCodecServer::Create<Max98373Codec>(mock_i2c.GetProto(), std::move(gpio));
ASSERT_NOT_NULL(codec);
auto codec_proto = codec->GetProto();
SimpleCodecClient client;
client.SetProtocol(&codec_proto);
// Delay to test we don't do other init I2C writes in another thread.
zx::nanosleep(zx::deadline_after(zx::msec(100)));
ASSERT_OK(client.Reset());
codec->DdkAsyncRemove();
ASSERT_TRUE(tester.Ok());
codec.release()->DdkRelease(); // codec release managed by the DDK
mock_i2c.VerifyAndClear();
mock_gpio.VerifyAndClear();
}
TEST(Max98373Test, SetGainGood) {
fake_ddk::Bind tester;
mock_i2c::MockI2c mock_i2c;
mock_i2c.ExpectWriteStop({0x20, 0x3d, 0x40}); // -32dB.
ddk::GpioProtocolClient unused_gpio;
auto codec =
SimpleCodecServer::Create<Max98373Codec>(mock_i2c.GetProto(), std::move(unused_gpio));
ASSERT_NOT_NULL(codec);
auto codec_proto = codec->GetProto();
SimpleCodecClient client;
client.SetProtocol(&codec_proto);
GainState gain({.gain = -32.f, .muted = false, .agc_enabled = false});
client.SetGainState(gain);
// Make a 2-way call to make sure the server (we know single threaded) completed previous calls.
auto unused = client.GetInfo();
static_cast<void>(unused);
codec->DdkAsyncRemove();
ASSERT_TRUE(tester.Ok());
codec.release()->DdkRelease(); // codec release managed by the DDK
mock_i2c.VerifyAndClear();
}
TEST(Max98373Test, SetGainOurOfRangeLow) {
fake_ddk::Bind tester;
mock_i2c::MockI2c mock_i2c;
mock_i2c.ExpectWriteStop({0x20, 0x3d, 0x7f}); // -63.5dB.
ddk::GpioProtocolClient unused_gpio;
auto codec =
SimpleCodecServer::Create<Max98373Codec>(mock_i2c.GetProto(), std::move(unused_gpio));
ASSERT_NOT_NULL(codec);
auto codec_proto = codec->GetProto();
SimpleCodecClient client;
client.SetProtocol(&codec_proto);
GainState gain({.gain = -999.f, .muted = false, .agc_enabled = false});
client.SetGainState(gain);
// Make a 2-way call to make sure the server (we know single threaded) completed previous calls.
auto unused = client.GetInfo();
static_cast<void>(unused);
codec->DdkAsyncRemove();
ASSERT_TRUE(tester.Ok());
codec.release()->DdkRelease(); // codec release managed by the DDK
mock_i2c.VerifyAndClear();
}
TEST(Max98373Test, SetGainOurOfRangeHigh) {
fake_ddk::Bind tester;
mock_i2c::MockI2c mock_i2c;
mock_i2c.ExpectWriteStop({0x20, 0x3d, 0x00}); // 0dB.
ddk::GpioProtocolClient unused_gpio;
auto codec =
SimpleCodecServer::Create<Max98373Codec>(mock_i2c.GetProto(), std::move(unused_gpio));
ASSERT_NOT_NULL(codec);
auto codec_proto = codec->GetProto();
SimpleCodecClient client;
client.SetProtocol(&codec_proto);
GainState gain({.gain = 999.f, .muted = false, .agc_enabled = false});
client.SetGainState(gain);
// Make a 2-way call to make sure the server (we know single threaded) completed previous calls.
auto unused = client.GetInfo();
static_cast<void>(unused);
codec->DdkAsyncRemove();
ASSERT_TRUE(tester.Ok());
codec.release()->DdkRelease(); // codec release managed by the DDK
mock_i2c.VerifyAndClear();
}
} // namespace audio