blob: 1694ad1c63724aca05c4e48eb546c6d75aef68c5 [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.
#ifndef SRC_DEVICES_POWER_DRIVERS_POWER_POWER_H_
#define SRC_DEVICES_POWER_DRIVERS_POWER_POWER_H_
#include <memory>
#include <vector>
#include <ddk/platform-defs.h>
#include <ddktl/device.h>
#include <ddktl/protocol/empty-protocol.h>
#include <ddktl/protocol/power.h>
#include <ddktl/protocol/powerimpl.h>
#include <fbl/mutex.h>
namespace power {
class PowerDeviceComponentChild;
class PowerDevice;
using PowerDeviceType = ddk::Device<PowerDevice, ddk::Unbindable, ddk::Multibindable>;
// Each power domain is modelled to be a power device and the power device class talks to
// a driver that implements ZX_PROTOCOL_POWER_IMPL, passing in the index of this power domain.
// For each dependent composite device of a PowerDevice(power domain), a PowerDeviceComponentChild
// is created.
class PowerDevice : public PowerDeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_POWER> {
public:
PowerDevice(zx_device_t* parent, uint32_t index, const ddk::PowerImplProtocolClient& power_impl,
const ddk::PowerProtocolClient& parent_power, uint32_t min_voltage,
uint32_t max_voltage, bool fixed)
: PowerDeviceType(parent),
index_(index),
power_impl_(power_impl),
parent_power_(parent_power),
min_voltage_uV_(min_voltage),
max_voltage_uV_(max_voltage),
fixed_(fixed) {}
static zx_status_t Create(void* ctx, zx_device_t* parent);
void DdkUnbind(ddk::UnbindTxn txn);
zx_status_t DdkOpenProtocolSessionMultibindable(uint32_t proto_id, void* ctx);
zx_status_t DdkCloseProtocolSessionMultibindable(void* child_ctx);
void DdkRelease();
zx_status_t RegisterPowerDomain(uint64_t component_device_id, uint32_t min_needed_voltage_uV,
uint32_t max_supported_voltage_uV);
zx_status_t UnregisterPowerDomain(uint64_t component_device_id);
zx_status_t GetPowerDomainStatus(uint64_t component_device_id, power_domain_status_t* out_status);
zx_status_t GetSupportedVoltageRange(uint64_t component_device_id, uint32_t* min_voltage,
uint32_t* max_voltage);
zx_status_t RequestVoltage(uint64_t component_device_id, uint32_t voltage,
uint32_t* actual_voltage);
zx_status_t GetCurrentVoltage(uint64_t component_device_id, uint32_t index,
uint32_t* current_voltage);
zx_status_t WritePmicCtrlReg(uint64_t component_device_id, uint32_t reg_addr, uint32_t value);
zx_status_t ReadPmicCtrlReg(uint64_t component_device_id, uint32_t reg_addr, uint32_t* out_value);
uint32_t GetDependentCount();
private:
PowerDeviceComponentChild* GetComponentChildLocked(uint64_t component_device_id)
__TA_REQUIRES(power_device_lock_);
zx_status_t GetSuitableVoltageLocked(uint32_t voltage, uint32_t* suitable_voltage)
__TA_REQUIRES(power_device_lock_);
uint32_t GetDependentCountLocked() __TA_REQUIRES(power_device_lock_);
const uint32_t index_;
const ddk::PowerImplProtocolClient power_impl_;
const ddk::PowerProtocolClient parent_power_;
fbl::Mutex power_device_lock_;
std::vector<std::unique_ptr<PowerDeviceComponentChild>> children_;
// Min supported voltage of this domain
uint32_t min_voltage_uV_;
// Max supported voltage of this domain
uint32_t max_voltage_uV_;
// Does it support voltage modifications?
bool fixed_;
};
// For each composite device that is dependent on a PowerDevice(power domain),
// an object of this class is created. This class maintains the context that is specific
// to the composite device. All the power protocol ops made by the composite device first
// arrive on this calss and are forwarded to the PowerDevice with the corresponding composite
// device context(component_device_id).
class PowerDeviceComponentChild
: public ddk::PowerProtocol<PowerDeviceComponentChild, ddk::base_protocol> {
public:
explicit PowerDeviceComponentChild(uint64_t component_device_id, PowerDevice* parent)
: component_device_id_(component_device_id), power_device_(parent) {}
zx_status_t PowerRegisterPowerDomain(uint32_t min_needed_voltage_uV,
uint32_t max_supported_voltage_uV);
zx_status_t PowerUnregisterPowerDomain();
zx_status_t PowerGetPowerDomainStatus(power_domain_status_t* out_status);
zx_status_t PowerGetSupportedVoltageRange(uint32_t* min_voltage, uint32_t* max_voltage);
zx_status_t PowerRequestVoltage(uint32_t voltage, uint32_t* actual_voltage);
zx_status_t PowerGetCurrentVoltage(uint32_t index, uint32_t* current_voltage);
zx_status_t PowerWritePmicCtrlReg(uint32_t reg_addr, uint32_t value);
zx_status_t PowerReadPmicCtrlReg(uint32_t reg_addr, uint32_t* out_value);
uint64_t component_device_id() const { return component_device_id_; }
power_protocol_ops_t* ops() { return &power_protocol_ops_; }
uint32_t min_needed_voltage_uV() const { return min_needed_voltage_uV_; }
uint32_t max_supported_voltage_uV() const { return max_supported_voltage_uV_; }
void set_min_needed_voltage_uV(uint32_t voltage) { min_needed_voltage_uV_ = voltage; }
void set_max_supported_voltage_uV(uint32_t voltage) { max_supported_voltage_uV_ = voltage; }
bool registered() const { return registered_; }
void set_registered(bool value) { registered_ = value; }
private:
uint64_t component_device_id_;
PowerDevice* power_device_;
uint32_t min_needed_voltage_uV_ = 0;
uint32_t max_supported_voltage_uV_ = 0;
bool registered_ = false;
};
} // namespace power
#endif // SRC_DEVICES_POWER_DRIVERS_POWER_POWER_H_