1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddk/protocol/i2c.h> 6#include <fbl/algorithm.h> 7#include <fbl/alloc_checker.h> 8 9#include "tas27xx.h" 10 11namespace audio { 12namespace astro { 13 14// static 15fbl::unique_ptr<Tas27xx> Tas27xx::Create(ddk::I2cChannel&& i2c) { 16 if (!i2c.is_valid()) { 17 return nullptr; 18 } 19 20 fbl::AllocChecker ac; 21 22 auto ptr = fbl::unique_ptr<Tas27xx>(new (&ac) Tas27xx()); 23 if (!ac.check()) { 24 return nullptr; 25 } 26 ptr->i2c_ = fbl::move(i2c); 27 28 return ptr; 29} 30 31zx_status_t Tas27xx::Reset() { 32 return WriteReg(SW_RESET, 0x01); 33} 34 35zx_status_t Tas27xx::SetGain(float gain) { 36 gain = fbl::clamp(gain, GetMinGain(), GetMaxGain()); 37 uint8_t gain_reg = static_cast<uint8_t>(-gain / kGainStep); 38 39 zx_status_t status; 40 status = WriteReg(PB_CFG2, gain_reg); 41 if (status == ZX_OK) { 42 current_gain_ = gain; 43 } 44 return status; 45} 46 47bool Tas27xx::ValidGain(float gain) { 48 return (gain <= kMaxGain) && (gain >= kMinGain); 49} 50 51zx_status_t Tas27xx::Init() { 52 zx_status_t status; 53 54 //Put part in active, but muted state 55 Standby(); 56 57 // 128 clocks per frame, manually configure dividers 58 status = WriteReg(CLOCK_CFG, (0x06 << 2) | 1); 59 if (status != ZX_OK) 60 return status; 61 62 // 48kHz, FSYNC on high to low transition 63 // Disable autorate detection 64 status = WriteReg(TDM_CFG0, (1 << 4) | (0x03 << 1) | 1); 65 if (status != ZX_OK) 66 return status; 67 68 // Left justified, offset 0 bclk, clock on falling edge of sclk 69 // our fsync is on falling edge, so first bit after falling edge is valid 70 status = WriteReg(TDM_CFG1, (0 << 1) | 1); 71 if (status != ZX_OK) 72 return status; 73 74 // Mono (L+R)/2, 32bit sample, 32bit slot 75 status = WriteReg(TDM_CFG2, (0x03 << 4) | (0x00 << 2) | 0x03); 76 if (status != ZX_OK) 77 return status; 78 79 // Left channel slot 0, Right channel slot 1 80 status = WriteReg(TDM_CFG3, (1 << 4) | 0); 81 if (status != ZX_OK) 82 return status; 83 84 // Initial gain -20db 85 SetGain(-20); 86 87 // Disable v and i sense, enter active mode 88 status = WriteReg(PWR_CTL, (0x03 << 2)); 89 if (status != ZX_OK) 90 return status; 91 92 return ZX_OK; 93} 94 95//Standby puts the part in active, but muted state 96zx_status_t Tas27xx::Standby() { 97 return WriteReg(PWR_CTL, (0x03 << 2) | 0x01); 98} 99 100zx_status_t Tas27xx::ExitStandby() { 101 return WriteReg(PWR_CTL, (0x03 << 2)); 102} 103 104uint8_t Tas27xx::ReadReg(uint8_t reg) { 105 uint8_t val; 106 i2c_.Read(reg, &val, 1); 107 return val; 108} 109 110zx_status_t Tas27xx::WriteReg(uint8_t reg, uint8_t value) { 111 uint8_t write_buf[2]; 112 write_buf[0] = reg; 113 write_buf[1] = value; 114 return i2c_.Write(write_buf, 2); 115} 116} //namespace astro 117} //namespace audio 118