blob: 2c432e4af50e549f605246c56af60a3ad1bac118 [file] [log] [blame]
// 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_