| // 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. |
| |
| #include "aml-thermal.h" |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/fake_ddk/fake_ddk.h> |
| |
| #include <mock/ddktl/protocol/gpio.h> |
| #include <mock/ddktl/protocol/scpi.h> |
| #include <zxtest/zxtest.h> |
| |
| namespace { |
| |
| bool FloatNear(float a, float b) { return std::abs(a - b) < 0.001f; } |
| |
| constexpr fuchsia_hardware_thermal_ThermalTemperatureInfo TripPointInfo( |
| float up_temp, float down_temp, uint16_t big_cluster_dvfs_opp, |
| uint16_t little_cluster_dvfs_opp) { |
| return {.up_temp_celsius = up_temp, |
| .down_temp_celsius = down_temp, |
| .fan_level = 0, |
| .big_cluster_dvfs_opp = big_cluster_dvfs_opp, |
| .little_cluster_dvfs_opp = little_cluster_dvfs_opp, |
| .gpu_clk_freq_source = 0}; |
| } |
| |
| // vim2 thermal device info. |
| constexpr fuchsia_hardware_thermal_ThermalDeviceInfo kDeviceInfo = { |
| .active_cooling = true, |
| .passive_cooling = true, |
| .gpu_throttling = true, |
| .num_trip_points = 8, |
| .big_little = true, |
| .critical_temp_celsius = 81.0f, |
| .trip_point_info = |
| { |
| TripPointInfo(2.0f, 0.0f, 6, 4), |
| TripPointInfo(65.0f, 63.0f, 6, 4), |
| TripPointInfo(70.0f, 68.0f, 6, 4), |
| TripPointInfo(75.0f, 73.0f, 6, 4), |
| TripPointInfo(82.0f, 79.0f, 5, 4), |
| TripPointInfo(87.0f, 84.0f, 4, 4), |
| TripPointInfo(92.0f, 89.0f, 3, 3), |
| TripPointInfo(96.0f, 93.0f, 2, 2), |
| }, |
| .opps = {}, |
| }; |
| |
| } // namespace |
| |
| namespace thermal { |
| |
| // Customize ddk::MockScpi to allow ScpiGetSensorValue to return a default value after all |
| // expectations have been used. |
| |
| class MockScpi : public ddk::MockScpi { |
| public: |
| MockScpi& ExpectGetSensorValue(zx_status_t out_s, uint32_t sensor_id, |
| uint32_t out_sensor_value) override { |
| last_sensor_value_ = {out_s, out_sensor_value}; |
| get_sensor_value_expectations_++; |
| |
| ddk::MockScpi::ExpectGetSensorValue(out_s, sensor_id, out_sensor_value); |
| return *this; |
| } |
| |
| zx_status_t ScpiGetSensorValue(uint32_t sensor_id, uint32_t* out_sensor_value) override { |
| if (get_sensor_value_expectations_ == 0) { |
| *out_sensor_value = std::get<1>(last_sensor_value_); |
| return std::get<0>(last_sensor_value_); |
| } |
| |
| get_sensor_value_expectations_--; |
| return ddk::MockScpi::ScpiGetSensorValue(sensor_id, out_sensor_value); |
| } |
| |
| private: |
| uint32_t get_sensor_value_expectations_ = 0; |
| std::tuple<zx_status_t, uint32_t> last_sensor_value_ = {ZX_OK, 0}; |
| }; |
| |
| class AmlThermalTest : public zxtest::Test { |
| public: |
| AmlThermalTest() : loop_(&kAsyncLoopConfigAttachToCurrentThread) {} |
| |
| void StartFidlServer(AmlThermal* device) { |
| zx::channel server; |
| ASSERT_OK(zx::channel::create(0, &client_, &server)); |
| ASSERT_OK( |
| fidl_bind(loop_.dispatcher(), server.release(), |
| reinterpret_cast<fidl_dispatch_t*>(fuchsia_hardware_thermal_Device_dispatch), |
| device, &AmlThermal::fidl_ops)); |
| ASSERT_OK(loop_.StartThread("aml-thermal-test-loop")); |
| } |
| |
| protected: |
| zx::channel client_; |
| |
| private: |
| async::Loop loop_; |
| }; |
| |
| TEST_F(AmlThermalTest, GetDvfsInfo) { |
| constexpr scpi_opp_t kExpectedBigClusterOpp = { |
| .opp = |
| { |
| [0] = {.freq_hz = 500'000'000, .volt_uv = 900'000}, |
| [1] = {.freq_hz = 750'000'000, .volt_uv = 900'000}, |
| [2] = {.freq_hz = 1'000'000'000, .volt_uv = 1'000'000}, |
| [3] = {.freq_hz = 1'100'000'000, .volt_uv = 1'000'000}, |
| [4] = {.freq_hz = 1'200'000'000, .volt_uv = 1'100'000}, |
| }, |
| .latency = 100, |
| .count = 5}; |
| |
| constexpr scpi_opp_t kExpectedLittleClusterOpp = { |
| .opp = |
| { |
| [0] = {.freq_hz = 500'000'000, .volt_uv = 800'000}, |
| [1] = {.freq_hz = 650'000'000, .volt_uv = 900'000}, |
| [2] = {.freq_hz = 900'000'000, .volt_uv = 1'000'000}, |
| }, |
| .latency = 200, |
| .count = 3}; |
| |
| MockScpi scpi; |
| AmlThermal dut(nullptr, {}, {}, scpi.GetProto(), 0, zx::port(), fake_ddk::kFakeDevice); |
| |
| ASSERT_NO_FATAL_FAILURES(StartFidlServer(&dut)); |
| |
| scpi.ExpectGetDvfsInfo(ZX_ERR_IO, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, |
| kExpectedBigClusterOpp) |
| .ExpectGetDvfsInfo(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, |
| kExpectedBigClusterOpp) |
| .ExpectGetDvfsInfo(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, |
| kExpectedLittleClusterOpp); |
| |
| zx_status_t status; |
| fuchsia_hardware_thermal_OperatingPoint out_opp; |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsInfo( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status, |
| &out_opp)); |
| EXPECT_EQ(status, ZX_ERR_IO); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsInfo( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status, |
| &out_opp)); |
| EXPECT_OK(status); |
| EXPECT_BYTES_EQ(&out_opp, &kExpectedBigClusterOpp, sizeof(scpi_opp_t)); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsInfo( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, &status, |
| &out_opp)); |
| EXPECT_OK(status); |
| EXPECT_BYTES_EQ(&out_opp, &kExpectedLittleClusterOpp, sizeof(scpi_opp_t)); |
| |
| scpi.VerifyAndClear(); |
| } |
| |
| TEST_F(AmlThermalTest, DvfsOperatingPoint) { |
| MockScpi scpi; |
| AmlThermal dut(nullptr, {}, {}, scpi.GetProto(), 0, zx::port(), fake_ddk::kFakeDevice); |
| |
| ASSERT_NO_FATAL_FAILURES(StartFidlServer(&dut)); |
| |
| scpi.ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, 1) |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, 3) |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, 0) |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, 10) |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, 7); |
| |
| zx_status_t status; |
| uint16_t op_idx; |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 1, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsOperatingPoint( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status, |
| &op_idx)); |
| EXPECT_OK(status); |
| EXPECT_EQ(op_idx, 1); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 3, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsOperatingPoint( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, &status, |
| &op_idx)); |
| EXPECT_OK(status); |
| EXPECT_EQ(op_idx, 3); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 0, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsOperatingPoint( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status, |
| &op_idx)); |
| EXPECT_OK(status); |
| EXPECT_EQ(op_idx, 0); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 0, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 10, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, |
| &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsOperatingPoint( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, &status, |
| &op_idx)); |
| EXPECT_OK(status); |
| EXPECT_EQ(op_idx, 10); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 10, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, |
| &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetDvfsOperatingPoint( |
| client_.get(), 7, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetDvfsOperatingPoint( |
| client_.get(), fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, &status, |
| &op_idx)); |
| EXPECT_OK(status); |
| EXPECT_EQ(op_idx, 7); |
| |
| scpi.VerifyAndClear(); |
| } |
| |
| TEST_F(AmlThermalTest, FanLevel) { |
| ddk::MockGpio fan0, fan1; |
| AmlThermal dut(nullptr, fan0.GetProto(), fan1.GetProto(), {}, 0, zx::port(), |
| fake_ddk::kFakeDevice); |
| |
| ASSERT_NO_FATAL_FAILURES(StartFidlServer(&dut)); |
| |
| fan0.ExpectWrite(ZX_OK, 0) |
| .ExpectWrite(ZX_OK, 0) |
| .ExpectWrite(ZX_OK, 1) |
| .ExpectWrite(ZX_OK, 1) |
| .ExpectWrite(ZX_OK, 0); |
| fan1.ExpectWrite(ZX_OK, 0) |
| .ExpectWrite(ZX_OK, 1) |
| .ExpectWrite(ZX_OK, 0) |
| .ExpectWrite(ZX_OK, 1) |
| .ExpectWrite(ZX_OK, 0); |
| |
| zx_status_t status; |
| uint32_t fan_level; |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetFanLevel(client_.get(), FAN_L0, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetFanLevel(client_.get(), &status, &fan_level)); |
| EXPECT_OK(status); |
| EXPECT_EQ(fan_level, FAN_L0); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetFanLevel(client_.get(), FAN_L2, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetFanLevel(client_.get(), &status, &fan_level)); |
| EXPECT_OK(status); |
| EXPECT_EQ(fan_level, FAN_L2); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetFanLevel(client_.get(), FAN_L1, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetFanLevel(client_.get(), &status, &fan_level)); |
| EXPECT_OK(status); |
| EXPECT_EQ(fan_level, FAN_L1); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetFanLevel(client_.get(), FAN_L3, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetFanLevel(client_.get(), &status, &fan_level)); |
| EXPECT_OK(status); |
| EXPECT_EQ(fan_level, FAN_L3); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceSetFanLevel(client_.get(), FAN_L0, &status)); |
| EXPECT_OK(status); |
| |
| EXPECT_OK(fuchsia_hardware_thermal_DeviceGetFanLevel(client_.get(), &status, &fan_level)); |
| EXPECT_OK(status); |
| EXPECT_EQ(fan_level, FAN_L0); |
| |
| fan0.VerifyAndClear(); |
| fan1.VerifyAndClear(); |
| } |
| |
| TEST_F(AmlThermalTest, TripPointThread) { |
| fake_ddk::Bind ddk; |
| ddk.SetMetadata(&kDeviceInfo, sizeof(kDeviceInfo)); |
| |
| ddk::MockGpio fan0, fan1; |
| MockScpi scpi; |
| |
| zx::port port; |
| ASSERT_OK(zx::port::create(0, &port)); |
| |
| AmlThermal dut(fake_ddk::kFakeDevice, fan0.GetProto(), fan1.GetProto(), scpi.GetProto(), 1234, |
| std::move(port), fake_ddk::kFakeDevice, zx::msec(10)); |
| |
| ASSERT_NO_FATAL_FAILURES(StartFidlServer(&dut)); |
| |
| zx_status_t status; |
| |
| ASSERT_OK(fuchsia_hardware_thermal_DeviceGetStateChangePort(client_.get(), &status, |
| port.reset_and_get_address())); |
| ASSERT_OK(status); |
| ASSERT_TRUE(port.is_valid()); |
| |
| fan0.ExpectConfigOut(ZX_OK, 0); |
| fan1.ExpectConfigOut(ZX_OK, 0); |
| |
| scpi.ExpectGetDvfsInfo(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, {}) |
| .ExpectGetDvfsInfo(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, |
| {}) |
| .ExpectGetSensorValue(ZX_OK, 1234, 30.0f) // Trip point 0 |
| .ExpectGetSensorValue(ZX_OK, 1234, 75.0f) // 0 -> 1 |
| .ExpectGetSensorValue(ZX_OK, 1234, 75.0f) // 1 -> 2 |
| .ExpectGetSensorValue(ZX_OK, 1234, 75.0f) // 2 -> 3 |
| .ExpectGetSensorValue(ZX_OK, 1234, 67.0f) // 3 -> 2 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 2 -> 3 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 3 -> 4 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 4 -> 5 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 5 -> 6 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 6 -> 7 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 7 -> critical |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, 0) |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, 0) |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) |
| .ExpectGetSensorValue(ZX_OK, 1234, 78.0f) // 7 -> 6 |
| .ExpectGetSensorValue(ZX_OK, 1234, 78.0f) // 6 -> 5 |
| .ExpectGetSensorValue(ZX_OK, 1234, 78.0f) // 5 -> 4 |
| .ExpectGetSensorValue(ZX_OK, 1234, 87.0f) // 4 -> 5 |
| .ExpectGetSensorValue(ZX_OK, 1234, 87.0f) |
| .ExpectGetSensorValue(ZX_OK, 1234, 87.0f) |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 5 -> 6 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 6 -> 7 |
| .ExpectGetSensorValue(ZX_OK, 1234, 96.0f) // 7 -> critical |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, 0) |
| .ExpectSetDvfsIdx(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, 0); |
| |
| ASSERT_OK(dut.Init(fake_ddk::kFakeDevice)); |
| |
| zx_port_packet_t packet; |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 0); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 1); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 2); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 3); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 2); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 3); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 4); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 5); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 6); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 7); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 7); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 6); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 5); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 4); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 5); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 6); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 7); |
| |
| ASSERT_OK(port.wait(zx::time::infinite(), &packet)); |
| EXPECT_EQ(packet.key, 7); |
| |
| float temperature; |
| |
| ASSERT_OK( |
| fuchsia_hardware_thermal_DeviceGetTemperatureCelsius(client_.get(), &status, &temperature)); |
| ASSERT_OK(status); |
| ASSERT_TRUE(FloatNear(temperature, 96.0f)); |
| |
| dut.DdkUnbind(ddk::UnbindTxn(fake_ddk::kFakeDevice)); |
| dut.JoinWorkerThread(); |
| |
| fan0.VerifyAndClear(); |
| fan1.VerifyAndClear(); |
| scpi.VerifyAndClear(); |
| } |
| |
| TEST_F(AmlThermalTest, DdkLifecycle) { |
| fake_ddk::Bind ddk; |
| ddk.SetMetadata(&kDeviceInfo, sizeof(kDeviceInfo)); |
| |
| ddk::MockGpio fan0, fan1; |
| MockScpi scpi; |
| |
| zx::port port; |
| ASSERT_OK(zx::port::create(0, &port)); |
| |
| AmlThermal dut(fake_ddk::kFakeParent, fan0.GetProto(), fan1.GetProto(), scpi.GetProto(), 1234, |
| std::move(port), fake_ddk::kFakeDevice, zx::msec(10)); |
| |
| fan0.ExpectConfigOut(ZX_OK, 0); |
| fan1.ExpectConfigOut(ZX_OK, 0); |
| |
| scpi.ExpectGetDvfsInfo(ZX_OK, fuchsia_hardware_thermal_PowerDomain_BIG_CLUSTER_POWER_DOMAIN, {}) |
| .ExpectGetDvfsInfo(ZX_OK, fuchsia_hardware_thermal_PowerDomain_LITTLE_CLUSTER_POWER_DOMAIN, |
| {}); |
| |
| // The DdkInit hook will run after DdkAdd. |
| dut.DdkAdd("vim-thermal"); |
| dut.DdkAsyncRemove(); |
| |
| EXPECT_TRUE(ddk.Ok()); |
| |
| // Join the worker thread spawned during the DdkInit hook. |
| dut.JoinWorkerThread(); |
| |
| fan0.VerifyAndClear(); |
| fan1.VerifyAndClear(); |
| scpi.VerifyAndClear(); |
| } |
| |
| } // namespace thermal |