blob: 5672914a042f40eebe238118785edff0613f4b7b [file] [log] [blame]
// Copyright 2017 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 <string.h>
#include <ddk/protocol/i2c-lib.h>
#include <fbl/algorithm.h>
#include "tas5720.h"
namespace audio {
constexpr float Tas5720::kMaxGain;
constexpr float Tas5720::kMinGain;
// clang-format off
constexpr uint8_t kRegPowerControl = 0x01;
constexpr uint8_t kRegDigitalControl1 = 0x02;
constexpr uint8_t kRegDigitalControl2 = 0x03;
constexpr uint8_t kRegVolumeControl = 0x04;
constexpr uint8_t kRegAnalogControl = 0x06;
constexpr uint8_t kRegFaultCfgErrorStatus = 0x08;
constexpr uint8_t kRegDigitalClipper2 = 0x10;
constexpr uint8_t kRegDigitalClipper1 = 0x11;
// clang-format on
// static
fbl::unique_ptr<Tas5720> Tas5720::Create(ddk::PDev pdev, uint32_t index) {
auto i2c = pdev.GetI2c(index);
if (i2c.is_valid()) {
zxlogf(ERROR, "%s pdev_get_protocol failed\n", __FUNCTION__);
return nullptr;
}
fbl::AllocChecker ac;
auto ptr = fbl::make_unique_checked<Tas5720>(&ac, i2c);
if (!ac.check()) {
return nullptr;
}
return ptr;
}
zx_status_t Tas5720::Reset() {
return ZX_OK;
}
zx_status_t Tas5720::SetGain(float gain) {
gain = fbl::clamp(gain, kMinGain, kMaxGain);
// Datasheet: "DVC [Hex Value] = 0xCF + (DVC [dB] / 0.5 [dB] )".
uint8_t gain_reg = static_cast<uint8_t>(0xCF + gain / .5f);
zx_status_t status;
status = WriteReg(kRegVolumeControl, gain_reg);
if (status != ZX_OK) {
return status;
}
current_gain_ = gain;
return status;
}
bool Tas5720::ValidGain(float gain) {
return (gain <= kMaxGain) && (gain >= kMinGain);
}
zx_status_t Tas5720::Init(uint8_t slot) {
Standby();
WriteReg(kRegDigitalControl1, 0x45); // Use Slot, Stereo Left Justified.
WriteReg(kRegDigitalControl2, slot & 0x07); // Slot.
WriteReg(kRegAnalogControl, 0x55); // PWM rate 16 x lrclk, gain 20.7 dBV.
WriteReg(kRegDigitalClipper2, 0xFF); // Disabled.
WriteReg(kRegDigitalClipper1, 0xFC); // Disabled.
ExitStandby();
uint8_t val = 0;
ReadReg(kRegFaultCfgErrorStatus, &val);
if (val != 0x00) {
return ZX_ERR_INTERNAL;
}
return ZX_OK;
}
zx_status_t Tas5720::Standby() {
uint8_t r;
ReadReg(kRegPowerControl, &r);
r = static_cast<uint8_t>(r & ~(0x01)); // SPK_SD.
r = static_cast<uint8_t>(r | (0x02)); // SPK_SLEEP.
WriteReg(kRegPowerControl, r);
return ZX_OK;
}
zx_status_t Tas5720::ExitStandby() {
uint8_t r;
ReadReg(kRegPowerControl, &r);
r = static_cast<uint8_t>(r | 0x01); // SPK_SD.
WriteReg(kRegPowerControl, r);
r = static_cast<uint8_t>(r & ~(0x02)); // SPK_SLEEP.
WriteReg(kRegPowerControl, r);
return ZX_OK;
}
zx_status_t Tas5720::WriteReg(uint8_t reg, uint8_t value) {
uint8_t write_buf[2];
write_buf[0] = reg;
write_buf[1] = value;
return i2c_.WriteSync(write_buf, 2);
}
zx_status_t Tas5720::ReadReg(uint8_t reg, uint8_t* value) {
return i2c_.WriteReadSync(&reg, 1, value, 1);
}
} // audio