blob: 2a3598d79ed794a18f509dcae1c86995eed7c971 [file] [log] [blame]
// Copyright 2023 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_I2C_DRIVERS_AML_I2C_AML_I2C_REGS_H_
#define SRC_DEVICES_I2C_DRIVERS_AML_I2C_AML_I2C_REGS_H_
#include <zircon/assert.h>
#include <zircon/types.h>
#include <limits>
#include <hwreg/bitfields.h>
namespace aml_i2c {
constexpr zx_off_t kControlReg = 0x00;
constexpr zx_off_t kTargetAddrReg = 0x04;
constexpr zx_off_t kTokenList0Reg = 0x08;
constexpr zx_off_t kTokenList1Reg = 0x0c;
constexpr zx_off_t kWriteData0Reg = 0x10;
constexpr zx_off_t kWriteData1Reg = 0x14;
constexpr zx_off_t kReadData0Reg = 0x18;
constexpr zx_off_t kReadData1Reg = 0x1c;
class Control : public hwreg::RegisterBase<Control, uint32_t> {
public:
static constexpr uint32_t kQtrClkDlyMax = 0x3ff;
// There is a separate set of bits in the control register (QTR_CLK_EXT) that
// extends this field to 12 bits. Only expose the main 10-bit field in order
// to simplify the driver logic (delay values for normal bus frequencies won't
// use anywhere near 10 bits anyway).
DEF_FIELD(21, 12, qtr_clk_dly);
DEF_BIT(3, error);
DEF_BIT(2, status);
DEF_BIT(1, ack_ignore);
DEF_BIT(0, start);
static auto Get() { return hwreg::RegisterAddr<Control>(kControlReg); }
};
class TargetAddr : public hwreg::RegisterBase<TargetAddr, uint32_t> {
public:
static constexpr uint32_t kSclLowDelayMax = 0xfff;
DEF_BIT(28, use_cnt_scl_low);
DEF_FIELD(27, 16, scl_low_dly);
DEF_FIELD(7, 1, target_address);
DEF_RSVDZ_BIT(0); // R/W bit, must be zero.
static auto Get() { return hwreg::RegisterAddr<TargetAddr>(kTargetAddrReg); }
};
class TokenList : public hwreg::RegisterBase<TokenList, uint64_t> {
public:
enum class Token : uint64_t {
kEnd,
kStart,
kTargetAddrWr,
kTargetAddrRd,
kData,
kDataLast,
kStop,
};
void Push(const Token token) {
ZX_ASSERT((kTokenSizeBits * token_count_) < std::numeric_limits<uint64_t>::digits);
const uint64_t token_mask = static_cast<uint64_t>(token) << (kTokenSizeBits * token_count_++);
set_reg_value(reg_value() | token_mask);
}
template <typename T>
TokenList& ReadFrom(T* reg_io) = delete;
template <typename T>
TokenList& WriteTo(T* reg_io) {
reg_io->Write32(reg_value() & std::numeric_limits<uint32_t>::max(), reg_addr());
reg_io->Write32(reg_value() >> std::numeric_limits<uint32_t>::digits,
reg_addr() + sizeof(uint32_t));
set_reg_value(0);
token_count_ = 0;
return *this;
}
static auto Get() { return hwreg::RegisterAddr<TokenList>(kTokenList0Reg); }
private:
static constexpr uint32_t kTokenSizeBits = 4;
uint32_t token_count_ = 0;
};
class WriteData : public hwreg::RegisterBase<WriteData, uint64_t> {
public:
static constexpr uint32_t kMaxWriteBytesPerTransfer = 8;
void Push(const uint8_t byte) {
ZX_ASSERT(byte_count_ < kMaxWriteBytesPerTransfer);
const uint64_t byte_mask = static_cast<uint64_t>(byte)
<< (std::numeric_limits<uint8_t>::digits * byte_count_++);
set_reg_value(reg_value() | byte_mask);
}
template <typename T>
WriteData& ReadFrom(T* reg_io) = delete;
template <typename T>
WriteData& WriteTo(T* reg_io) {
reg_io->Write32(reg_value() & std::numeric_limits<uint32_t>::max(), reg_addr());
reg_io->Write32(reg_value() >> std::numeric_limits<uint32_t>::digits,
reg_addr() + sizeof(uint32_t));
set_reg_value(0);
byte_count_ = 0;
return *this;
}
static auto Get() { return hwreg::RegisterAddr<WriteData>(kWriteData0Reg); }
private:
uint32_t byte_count_ = 0;
};
class ReadData : public hwreg::RegisterBase<ReadData, uint64_t> {
public:
static constexpr uint32_t kMaxReadBytesPerTransfer = 8;
uint8_t Pop() {
ZX_ASSERT(byte_count_ > 0);
byte_count_--;
const uint8_t byte = reg_value() & std::numeric_limits<uint8_t>::max();
set_reg_value(reg_value() >> std::numeric_limits<uint8_t>::digits);
return byte;
}
template <typename T>
ReadData& ReadFrom(T* reg_io) {
const uint64_t lower = reg_io->Read32(reg_addr());
const uint64_t upper = static_cast<uint64_t>(reg_io->Read32(reg_addr() + sizeof(uint32_t)))
<< std::numeric_limits<uint32_t>::digits;
set_reg_value(upper | lower);
byte_count_ = kMaxReadBytesPerTransfer;
return *this;
}
template <typename T>
ReadData& WriteTo(T* reg_io) {
ZX_ASSERT(reg_value() == 0);
reg_io->Write32(0, reg_addr());
reg_io->Write32(0, reg_addr() + sizeof(uint32_t));
return *this;
}
static auto Get() { return hwreg::RegisterAddr<ReadData>(kReadData0Reg); }
private:
uint32_t byte_count_ = 0;
};
} // namespace aml_i2c
#endif // SRC_DEVICES_I2C_DRIVERS_AML_I2C_AML_I2C_REGS_H_