blob: 4d1904ebc41788f417975083b9f40038571a79cd [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.
#pragma once
#include <lib/mmio/mmio.h>
#include <threads.h>
#include <array>
#include <ddktl/device.h>
#include <ddktl/protocol/platform/device.h>
#include <ddktl/protocol/powerimpl.h>
#include <fbl/vector.h>
#include <soc/mt8167/mt8167-power-regs.h>
#include <soc/mt8167/mt8167-power.h>
namespace power {
// Describes a voltage regulator
class MtkRegulator {
public:
MtkRegulator(ddk::MmioView pmic_mmio, const uint32_t default_voltage, const uint32_t enable_reg,
const uint8_t enable_bit)
: cur_voltage_(default_voltage),
default_voltage_(default_voltage),
enable_register_(enable_reg),
enable_bit_(enable_bit),
pmic_mmio_(pmic_mmio) {}
virtual ~MtkRegulator() {}
uint32_t enable_register() { return enable_register_; }
uint32_t cur_voltage() { return cur_voltage_; }
uint32_t default_voltage() { return default_voltage_; }
uint8_t enable_bit() { return enable_bit_; }
bool enabled() { return enabled_; }
zx_status_t Enable();
zx_status_t Disable();
virtual zx_status_t GetSupportedVoltageRange(uint32_t* min_voltage,
uint32_t* max_voltage) const = 0;
virtual zx_status_t RequestVoltage(uint32_t set_voltage, uint32_t* actual_voltage) = 0;
protected:
zx_status_t ReadPMICReg(uint32_t reg_addr, uint32_t* reg_value);
zx_status_t WritePMICReg(uint32_t reg_addr, uint32_t value);
uint32_t cur_voltage_;
private:
const uint32_t default_voltage_;
const uint32_t enable_register_;
const uint8_t enable_bit_;
ddk::MmioView pmic_mmio_;
bool enabled_ = false;
void WaitForIdle();
void WaitForValidClear();
};
class MtkBuckRegulator : public MtkRegulator {
public:
MtkBuckRegulator(ddk::MmioView pmic_mmio, const uint32_t enable_reg, const uint8_t enable_bit,
const uint32_t voltage_sel_reg, const uint32_t voltage_sel_mask,
const uint32_t voltage_sel_shift, const uint32_t buck_voltage_ctrl_reg,
const uint32_t buck_voltage_on_reg, const uint32_t min_voltage,
const uint32_t max_voltage, const uint32_t step_size)
: MtkRegulator(pmic_mmio, min_voltage, enable_reg, enable_bit),
buck_voltage_ctrl_reg_(buck_voltage_ctrl_reg),
buck_voltage_on_reg_(buck_voltage_on_reg),
voltage_sel_reg_(voltage_sel_reg),
voltage_sel_mask_(voltage_sel_mask),
voltage_sel_shift_(voltage_sel_shift),
min_voltage_(min_voltage),
max_voltage_(max_voltage),
step_size_(step_size) {}
uint32_t buck_voltage_ctrl_reg() { return buck_voltage_ctrl_reg_; }
uint32_t buck_voltage_on_reg() { return buck_voltage_on_reg_; }
uint32_t voltage_sel_reg() { return voltage_sel_reg_; }
uint32_t voltage_sel_mask() { return voltage_sel_mask_; }
uint32_t voltage_sel_shift() { return voltage_sel_shift_; }
uint32_t min_voltage() { return min_voltage_; }
uint32_t max_voltage() { return max_voltage_; }
uint32_t step_size() { return step_size_; }
zx_status_t GetSupportedVoltageRange(uint32_t* min_voltage,
uint32_t* max_voltage) const override {
*min_voltage = min_voltage_;
*max_voltage = max_voltage_;
return ZX_OK;
}
zx_status_t RequestVoltage(uint32_t voltage, uint32_t* actual_voltage) override;
zx_status_t SetVoltageSelReg();
private:
zx_status_t GetVoltageSelector(uint32_t set_voltage, uint32_t* actual_voltage,
uint16_t* selector);
const uint32_t buck_voltage_ctrl_reg_;
const uint32_t buck_voltage_on_reg_;
uint32_t voltage_sel_reg_;
const uint32_t voltage_sel_mask_;
const uint32_t voltage_sel_shift_;
const uint32_t min_voltage_;
const uint32_t max_voltage_;
const uint32_t step_size_;
};
class MtkLdoRegulator : public MtkRegulator {
public:
MtkLdoRegulator(ddk::MmioView pmic_mmio, const uint32_t enable_reg, const uint8_t enable_bit,
const uint32_t voltage_sel_reg, const uint32_t voltage_sel_mask,
const uint32_t voltage_sel_shift, const fbl::Vector<uint32_t>& supported_voltages)
: MtkRegulator(pmic_mmio, 0, enable_reg, enable_bit),
voltage_sel_reg_(voltage_sel_reg),
voltage_sel_mask_(voltage_sel_mask),
voltage_sel_shift_(voltage_sel_shift),
supported_voltages_(supported_voltages) {}
uint32_t voltage_sel_reg() { return voltage_sel_reg_; }
uint32_t voltage_sel_mask() { return voltage_sel_mask_; }
uint32_t voltage_sel_shift() { return voltage_sel_shift_; }
const fbl::Vector<uint32_t>& supported_voltages() { return supported_voltages_; }
zx_status_t GetSupportedVoltageRange(uint32_t* min_voltage,
uint32_t* max_voltage) const override {
if (supported_voltages_.is_empty()) {
return ZX_ERR_BAD_STATE;
}
*min_voltage = *(supported_voltages_.begin());
*max_voltage = supported_voltages_[supported_voltages_.size() - 1];
return ZX_OK;
}
zx_status_t RequestVoltage(uint32_t voltage, uint32_t* actual_voltage) override;
private:
zx_status_t GetVoltageSelector(uint32_t set_voltage, uint32_t* actual_voltage,
uint16_t* selector);
const uint32_t voltage_sel_reg_;
const uint32_t voltage_sel_mask_;
const uint32_t voltage_sel_shift_;
const fbl::Vector<uint32_t>& supported_voltages_;
};
class MtkFixedRegulator : public MtkRegulator {
public:
MtkFixedRegulator(ddk::MmioView pmic_mmio, const uint32_t default_voltage,
const uint32_t enable_reg, const uint8_t enable_bit)
: MtkRegulator(pmic_mmio, default_voltage, enable_reg, enable_bit) {}
zx_status_t GetSupportedVoltageRange(uint32_t* min_voltage,
uint32_t* max_voltage) const override {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t RequestVoltage(uint32_t voltage, uint32_t* actual_voltage) override {
return ZX_ERR_NOT_SUPPORTED;
}
};
class MtkPower;
using MtkPowerType = ddk::Device<MtkPower, ddk::UnbindableNew>;
class MtkPower : public MtkPowerType, public ddk::PowerImplProtocol<MtkPower, ddk::base_protocol> {
public:
explicit MtkPower(zx_device_t* parent, ddk::MmioBuffer mmio)
: MtkPowerType(parent), pmic_mmio_(std::move(mmio)) {}
~MtkPower() = default;
static zx_status_t Create(void* ctx, zx_device_t* parent);
// Device protocol implementation
void DdkRelease();
void DdkUnbindNew(ddk::UnbindTxn txn);
zx_status_t PowerImplGetPowerDomainStatus(uint32_t index, power_domain_status_t* out_status);
zx_status_t PowerImplEnablePowerDomain(uint32_t index);
zx_status_t PowerImplDisablePowerDomain(uint32_t index);
zx_status_t PowerImplGetSupportedVoltageRange(uint32_t index, uint32_t* min_voltage,
uint32_t* max_voltage);
zx_status_t PowerImplRequestVoltage(uint32_t index, uint32_t voltage, uint32_t* actual_voltage);
zx_status_t PowerImplGetCurrentVoltage(uint32_t index, uint32_t* current_voltage);
zx_status_t PowerImplWritePmicCtrlReg(uint32_t index, uint32_t addr, uint32_t value);
zx_status_t PowerImplReadPmicCtrlReg(uint32_t index, uint32_t addr, uint32_t* value);
protected:
void InitializePowerDomains();
std::array<std::unique_ptr<MtkRegulator>, kMt8167NumPowerDomains> power_domains_;
private:
ddk::MmioBuffer pmic_mmio_;
zx_status_t Bind();
zx_status_t Init();
void WaitForIdle();
void WaitForValidClear();
zx_status_t ReadPMICReg(uint32_t reg_addr, uint32_t* reg_value);
zx_status_t WritePMICReg(uint32_t reg_addr, uint32_t value);
};
} // namespace power