blob: d69d891ba53c0fecc5f8b9335e9ace0cebe89bef [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 <fidl/fuchsia.hardware.power/cpp/wire.h>
#include <fuchsia/hardware/powerimpl/cpp/banjo.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/ddk/platform-defs.h>
#include <zircon/compiler.h>
#include <memory>
#include <vector>
#include <ddktl/device.h>
#include <ddktl/protocol/empty-protocol.h>
#include <fbl/mutex.h>
namespace power {
class PowerDeviceFragmentChild;
class PowerDevice;
using PowerDeviceType = ddk::Device<PowerDevice>;
// 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 PowerDeviceFragmentChild
// is created.
class PowerDevice : public PowerDeviceType {
public:
PowerDevice(zx_device_t* parent, uint32_t index, const ddk::PowerImplProtocolClient& power_impl,
fidl::ClientEnd<fuchsia_hardware_power::Device> parent_power, uint32_t min_voltage,
uint32_t max_voltage, bool fixed)
: PowerDeviceType(parent),
index_(index),
power_impl_(power_impl),
parent_power_(std::move(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 DdkRelease();
zx_status_t RegisterPowerDomain(uint64_t fragment_device_id, uint32_t min_needed_voltage_uV,
uint32_t max_supported_voltage_uV);
zx_status_t UnregisterPowerDomain(uint64_t fragment_device_id);
zx_status_t GetPowerDomainStatus(uint64_t fragment_device_id, power_domain_status_t* out_status);
zx_status_t GetSupportedVoltageRange(uint64_t fragment_device_id, uint32_t* min_voltage,
uint32_t* max_voltage);
zx_status_t RequestVoltage(uint64_t fragment_device_id, uint32_t voltage,
uint32_t* actual_voltage);
zx_status_t GetCurrentVoltage(uint64_t fragment_device_id, uint32_t index,
uint32_t* current_voltage);
zx_status_t WritePmicCtrlReg(uint64_t fragment_device_id, uint32_t reg_addr, uint32_t value);
zx_status_t ReadPmicCtrlReg(uint64_t fragment_device_id, uint32_t reg_addr, uint32_t* out_value);
uint32_t GetDependentCount();
fit::function<void(fidl::ServerEnd<fuchsia_hardware_power::Device>)> GetHandler();
zx_status_t Serve(fidl::ServerEnd<fuchsia_io::Directory> server_end);
private:
PowerDeviceFragmentChild* GetFragmentChildLocked(uint64_t fragment_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_;
// This is optional. Check its validity before using.
fidl::ClientEnd<fuchsia_hardware_power::Device> parent_power_;
fbl::Mutex power_device_lock_;
std::vector<std::unique_ptr<PowerDeviceFragmentChild>> children_ __TA_GUARDED(power_device_lock_);
// 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_;
async_dispatcher_t* dispatcher_{fdf::Dispatcher::GetCurrent()->async_dispatcher()};
component::OutgoingDirectory outgoing_{dispatcher_};
fidl::ServerBindingGroup<fuchsia_hardware_power::Device> bindings_;
};
// 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(fragment_device_id).
class PowerDeviceFragmentChild : public fidl::WireServer<fuchsia_hardware_power::Device> {
public:
explicit PowerDeviceFragmentChild(uint64_t fragment_device_id, PowerDevice* parent)
: fragment_device_id_(fragment_device_id), power_device_(parent) {}
void RegisterPowerDomain(RegisterPowerDomainRequestView request,
RegisterPowerDomainCompleter::Sync& completer) override;
void UnregisterPowerDomain(UnregisterPowerDomainCompleter::Sync& completer) override;
void GetPowerDomainStatus(GetPowerDomainStatusCompleter::Sync& completer) override;
void GetSupportedVoltageRange(GetSupportedVoltageRangeCompleter::Sync& completer) override;
void RequestVoltage(RequestVoltageRequestView request,
RequestVoltageCompleter::Sync& completer) override;
void GetCurrentVoltage(GetCurrentVoltageRequestView request,
GetCurrentVoltageCompleter::Sync& completer) override;
void WritePmicCtrlReg(WritePmicCtrlRegRequestView request,
WritePmicCtrlRegCompleter::Sync& completer) override;
void ReadPmicCtrlReg(ReadPmicCtrlRegRequestView request,
ReadPmicCtrlRegCompleter::Sync& completer) override;
uint64_t fragment_device_id() const { return fragment_device_id_; }
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 fragment_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_