| // Copyright 2018 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. |
| |
| #include <fuchsia/hardware/thermal/c/fidl.h> |
| #include <lib/fidl-utils/bind.h> |
| #include <lib/sync/completion.h> |
| #include <lib/zx/port.h> |
| #include <threads.h> |
| |
| #include <utility> |
| |
| #include <ddk/device.h> |
| #include <ddktl/device.h> |
| #include <ddktl/protocol/empty-protocol.h> |
| #include <ddktl/protocol/gpio.h> |
| #include <ddktl/protocol/scpi.h> |
| #include <ddktl/protocol/thermal.h> |
| |
| #ifndef SRC_DEVICES_THERMAL_DRIVERS_AML_THERMAL_S912_AML_THERMAL_H_ |
| #define SRC_DEVICES_THERMAL_DRIVERS_AML_THERMAL_S912_AML_THERMAL_H_ |
| |
| namespace { |
| |
| // Worker-thread's internal loop wait duration in milliseconds. |
| constexpr zx::duration kDuration = zx::sec(5); |
| |
| } // namespace |
| |
| namespace thermal { |
| |
| enum FanLevel { |
| FAN_L0, |
| FAN_L1, |
| FAN_L2, |
| FAN_L3, |
| }; |
| |
| class AmlThermal; |
| using DeviceType = ddk::Device<AmlThermal, ddk::Initializable, ddk::Messageable, ddk::Unbindable>; |
| |
| // AmlThermal implements the s912 AmLogic thermal driver. |
| class AmlThermal : public DeviceType, public ddk::ThermalProtocol<AmlThermal, ddk::base_protocol> { |
| public: |
| AmlThermal(zx_device_t* device, const ddk::GpioProtocolClient& fan0_gpio, |
| const ddk::GpioProtocolClient& fan1_gpio, const ddk::ScpiProtocolClient& scpi, |
| const uint32_t sensor_id, zx::port port, zx_device_t* scpi_dev, |
| zx::duration duration = kDuration) |
| : DeviceType(device), |
| fan0_gpio_(fan0_gpio), |
| fan1_gpio_(fan1_gpio), |
| scpi_(scpi), |
| sensor_id_(sensor_id), |
| port_(std::move(port)), |
| scpi_dev_(scpi_dev), |
| duration_(duration) {} |
| |
| // Create and bind a driver instance. |
| static zx_status_t Create(void* ctx, zx_device_t* device); |
| |
| // Perform post-construction runtime initialization. |
| zx_status_t Init(zx_device_t* dev); |
| |
| // Ddk-required methods. |
| void DdkInit(ddk::InitTxn txn); |
| zx_status_t DdkMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn); |
| void DdkUnbind(ddk::UnbindTxn txn); |
| void DdkRelease(); |
| |
| // Implements ZX_PROTOCOL_THERMAL |
| zx_status_t ThermalConnect(zx::channel ch); |
| |
| // Visible for testing. |
| zx_status_t GetInfo(fidl_txn_t* txn); |
| zx_status_t GetDeviceInfo(fidl_txn_t* txn); |
| zx_status_t GetDvfsInfo(fuchsia_hardware_thermal_PowerDomain power_domain, fidl_txn_t* txn); |
| zx_status_t GetTemperatureCelsius(fidl_txn_t* txn); |
| zx_status_t GetStateChangeEvent(fidl_txn_t* txn); |
| zx_status_t GetStateChangePort(fidl_txn_t* txn); |
| zx_status_t SetTripCelsius(uint32_t id, float temp, fidl_txn_t* txn); |
| zx_status_t GetDvfsOperatingPoint(fuchsia_hardware_thermal_PowerDomain power_domain, |
| fidl_txn_t* txn); |
| zx_status_t SetDvfsOperatingPoint(uint16_t op_idx, |
| fuchsia_hardware_thermal_PowerDomain power_domain, |
| fidl_txn_t* txn); |
| zx_status_t GetFanLevel(fidl_txn_t* txn); |
| zx_status_t SetFanLevel(uint32_t fan_level, fidl_txn_t* txn); |
| |
| void JoinWorkerThread(); |
| |
| static constexpr fuchsia_hardware_thermal_Device_ops_t fidl_ops = { |
| .GetTemperatureCelsius = |
| fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetTemperatureCelsius>, |
| .GetInfo = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetInfo>, |
| .GetDeviceInfo = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetDeviceInfo>, |
| .GetDvfsInfo = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetDvfsInfo>, |
| .GetStateChangeEvent = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetStateChangeEvent>, |
| .GetStateChangePort = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetStateChangePort>, |
| .SetTripCelsius = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::SetTripCelsius>, |
| .GetDvfsOperatingPoint = |
| fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetDvfsOperatingPoint>, |
| .SetDvfsOperatingPoint = |
| fidl::Binder<AmlThermal>::BindMember<&AmlThermal::SetDvfsOperatingPoint>, |
| .GetFanLevel = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::GetFanLevel>, |
| .SetFanLevel = fidl::Binder<AmlThermal>::BindMember<&AmlThermal::SetFanLevel>, |
| }; |
| |
| private: |
| // Notification thread implementation. |
| int Worker(); |
| |
| // Set the fans to the given level. |
| zx_status_t SetFanLevel(FanLevel level); |
| |
| // Notify the thermal daemon of the current settings. |
| zx_status_t NotifyThermalDaemon(uint32_t trip_point) const; |
| |
| ddk::GpioProtocolClient fan0_gpio_; |
| ddk::GpioProtocolClient fan1_gpio_; |
| ddk::ScpiProtocolClient scpi_; |
| |
| uint32_t sensor_id_; |
| zx::port port_; |
| |
| zx_device_t* scpi_dev_; |
| |
| thrd_t worker_ = {}; |
| fuchsia_hardware_thermal_ThermalDeviceInfo info_ = {}; |
| FanLevel fan_level_ = FAN_L0; |
| float temperature_ = 0.0f; |
| sync_completion quit_; |
| uint32_t cur_bigcluster_opp_idx_ = 0; |
| uint32_t cur_littlecluster_opp_idx_ = 0; |
| const zx::duration duration_; |
| }; |
| |
| } // namespace thermal |
| |
| #endif // SRC_DEVICES_THERMAL_DRIVERS_AML_THERMAL_S912_AML_THERMAL_H_ |