| // 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_ |