| // Copyright 2023 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 "src/devices/power/drivers/fusb302/fusb302-controls.h" |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/inspect/cpp/vmo/types.h> |
| #include <lib/inspect/testing/cpp/zxtest/inspect.h> |
| #include <lib/mock-i2c/mock-i2c.h> |
| |
| #include <cstdint> |
| #include <optional> |
| #include <utility> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "src/devices/power/drivers/fusb302/fusb302-sensors.h" |
| #include "src/devices/power/drivers/fusb302/usb-pd-defs.h" |
| |
| namespace fusb302 { |
| |
| namespace { |
| |
| // Register addresses from Table 16 "Register Definitions" on page 18 of the |
| // Rev 5 datasheet. |
| constexpr int kSwitches0Address = 0x02; |
| constexpr int kSwitches1Address = 0x03; |
| constexpr int kMeasureAddress = 0x04; |
| constexpr int kControl0Address = 0x06; |
| constexpr int kControl1Address = 0x07; |
| constexpr int kControl2Address = 0x08; |
| constexpr int kControl3Address = 0x09; |
| constexpr int kPowerAddress = 0x0b; |
| constexpr int kResetAddress = 0x0c; |
| constexpr int kControl4Address = 0x10; |
| |
| class Fusb302ControlsTest : public inspect::InspectTestHelper, public zxtest::Test { |
| public: |
| void SetUp() override { |
| fdf::Logger::SetGlobalInstance(&logger_); |
| |
| auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>(); |
| EXPECT_TRUE(endpoints.is_ok()); |
| mock_i2c_client_ = std::move(endpoints->client); |
| |
| EXPECT_OK(loop_.StartThread()); |
| fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server), |
| &mock_i2c_); |
| |
| sensors_.emplace(mock_i2c_client_, inspect_.GetRoot().CreateChild("Sensors")); |
| controls_.emplace(mock_i2c_client_, sensors_.value(), |
| inspect_.GetRoot().CreateChild("Controls")); |
| } |
| |
| void TearDown() override { fdf::Logger::SetGlobalInstance(nullptr); } |
| |
| protected: |
| inspect::Inspector inspect_; |
| fdf::Logger logger_{"fusb302-controls-test", FUCHSIA_LOG_DEBUG, zx::socket{}, |
| fidl::WireClient<fuchsia_logger::LogSink>()}; |
| |
| async::Loop loop_{&kAsyncLoopConfigNeverAttachToThread}; |
| mock_i2c::MockI2c mock_i2c_; |
| fidl::ClientEnd<fuchsia_hardware_i2c::Device> mock_i2c_client_; |
| std::optional<Fusb302Sensors> sensors_; |
| std::optional<Fusb302Controls> controls_; |
| }; |
| |
| TEST_F(Fusb302ControlsTest, ResetIntoPowerRoleDiscoveryFromSoftwareResetState) { |
| mock_i2c_.ExpectWrite({kSwitches0Address}).ExpectReadStop({0x03}); |
| mock_i2c_.ExpectWrite({kSwitches1Address}).ExpectReadStop({0x20}); |
| mock_i2c_.ExpectWrite({kPowerAddress}).ExpectReadStop({0x01}); |
| mock_i2c_.ExpectWriteStop({kPowerAddress, 0x0f}); |
| |
| mock_i2c_.ExpectWrite({kControl0Address}).ExpectReadStop({0x24}); |
| mock_i2c_.ExpectWriteStop({kControl0Address, 0x04}); |
| mock_i2c_.ExpectWrite({kControl1Address}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWrite({kControl3Address}).ExpectReadStop({0x06}); |
| mock_i2c_.ExpectWriteStop({kControl3Address, 0x07}); |
| mock_i2c_.ExpectWrite({kControl4Address}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWrite({kMeasureAddress}).ExpectReadStop({0x31}); |
| mock_i2c_.ExpectWriteStop({kMeasureAddress, 0x30}); |
| |
| mock_i2c_.ExpectWrite({kControl2Address}).ExpectReadStop({0x02}); |
| mock_i2c_.ExpectWriteStop({kControl2Address, 0x23}); |
| |
| EXPECT_OK(controls_->ResetIntoPowerRoleDiscovery()); |
| } |
| |
| TEST_F(Fusb302ControlsTest, ResetIntoPowerRoleDiscoveryNoWrites) { |
| mock_i2c_.ExpectWrite({kSwitches0Address}).ExpectReadStop({0x03}); |
| mock_i2c_.ExpectWrite({kSwitches1Address}).ExpectReadStop({0x20}); |
| mock_i2c_.ExpectWrite({kPowerAddress}).ExpectReadStop({0x0f}); |
| mock_i2c_.ExpectWrite({kControl0Address}).ExpectReadStop({0x04}); |
| mock_i2c_.ExpectWrite({kControl1Address}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWrite({kControl3Address}).ExpectReadStop({0x07}); |
| mock_i2c_.ExpectWrite({kControl4Address}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWrite({kMeasureAddress}).ExpectReadStop({0x30}); |
| mock_i2c_.ExpectWrite({kControl2Address}).ExpectReadStop({0x23}); |
| |
| EXPECT_OK(controls_->ResetIntoPowerRoleDiscovery()); |
| EXPECT_EQ(usb_pd::ConfigChannelPinSwitch::kNone, controls_->wired_cc_pin()); |
| EXPECT_EQ(usb_pd::PowerRole::kSink, controls_->power_role()); |
| EXPECT_EQ(usb_pd::DataRole::kUpstreamFacingPort, controls_->data_role()); |
| EXPECT_EQ(usb_pd::SpecRevision::kRev2, controls_->spec_revision()); |
| } |
| |
| TEST_F(Fusb302ControlsTest, ResetIntoPowerRoleDiscoveryAllWrites) { |
| // The read values have all the documented bits set. Power's read value is |
| // zero, because the tested method sets all the documented bits, and we want |
| // to see it changing the register. |
| mock_i2c_.ExpectWrite({kSwitches0Address}).ExpectReadStop({0xff}); |
| mock_i2c_.ExpectWriteStop({kSwitches0Address, 0x03}); |
| mock_i2c_.ExpectWrite({kSwitches1Address}).ExpectReadStop({0xf7}); |
| mock_i2c_.ExpectWriteStop({kSwitches1Address, 0x20}); |
| mock_i2c_.ExpectWrite({kPowerAddress}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWriteStop({kPowerAddress, 0x0f}); |
| mock_i2c_.ExpectWrite({kControl0Address}).ExpectReadStop({0x6f}); |
| mock_i2c_.ExpectWriteStop({kControl0Address, 0x04}); |
| mock_i2c_.ExpectWrite({kControl1Address}).ExpectReadStop({0x77}); |
| mock_i2c_.ExpectWriteStop({kControl1Address, 0x00}); |
| mock_i2c_.ExpectWrite({kControl3Address}).ExpectReadStop({0x7f}); |
| mock_i2c_.ExpectWriteStop({kControl3Address, 0x07}); |
| mock_i2c_.ExpectWrite({kControl4Address}).ExpectReadStop({0x01}); |
| mock_i2c_.ExpectWriteStop({kControl4Address, 0x00}); |
| mock_i2c_.ExpectWrite({kMeasureAddress}).ExpectReadStop({0x7f}); |
| mock_i2c_.ExpectWriteStop({kMeasureAddress, 0x30}); |
| mock_i2c_.ExpectWrite({kControl2Address}).ExpectReadStop({0xef}); |
| mock_i2c_.ExpectWriteStop({kControl2Address, 0x23}); |
| |
| EXPECT_OK(controls_->ResetIntoPowerRoleDiscovery()); |
| } |
| |
| TEST_F(Fusb302ControlsTest, ConfigureAllRolesSinkOnCc1AllWrites) { |
| // The read values have all the documented bits set. Power's read value is |
| // zero, because the tested method sets all the documented bits, and we want |
| // to see it changing the register. |
| mock_i2c_.ExpectWrite({kControl2Address}).ExpectReadStop({0xef}); |
| mock_i2c_.ExpectWriteStop({kControl2Address, 0x22}); |
| mock_i2c_.ExpectWriteStop({kResetAddress, 0x02}); |
| mock_i2c_.ExpectWrite({kSwitches0Address}).ExpectReadStop({0xff}); |
| mock_i2c_.ExpectWriteStop({kSwitches0Address, 0x07}); |
| mock_i2c_.ExpectWrite({kSwitches1Address}).ExpectReadStop({0xf7}); |
| mock_i2c_.ExpectWriteStop({kSwitches1Address, 0x25}); |
| mock_i2c_.ExpectWrite({kPowerAddress}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWriteStop({kPowerAddress, 0x0f}); |
| mock_i2c_.ExpectWrite({kControl0Address}).ExpectReadStop({0x6f}); |
| mock_i2c_.ExpectWriteStop({kControl0Address, 0x40}); |
| mock_i2c_.ExpectWrite({kControl1Address}).ExpectReadStop({0x77}); |
| mock_i2c_.ExpectWriteStop({kControl1Address, 0x04}); |
| mock_i2c_.ExpectWrite({kControl3Address}).ExpectReadStop({0x7f}); |
| mock_i2c_.ExpectWriteStop({kControl3Address, 0x07}); |
| mock_i2c_.ExpectWrite({kControl4Address}).ExpectReadStop({0x01}); |
| mock_i2c_.ExpectWriteStop({kControl4Address, 0x00}); |
| mock_i2c_.ExpectWrite({kMeasureAddress}).ExpectReadStop({0x7f}); |
| mock_i2c_.ExpectWriteStop({kMeasureAddress, 0x30}); |
| |
| EXPECT_OK(controls_->ConfigureAllRoles( |
| usb_pd::ConfigChannelPinSwitch::kCc1, usb_pd::PowerRole::kSink, |
| usb_pd::DataRole::kUpstreamFacingPort, usb_pd::SpecRevision::kRev2)); |
| |
| EXPECT_EQ(usb_pd::ConfigChannelPinSwitch::kCc1, controls_->wired_cc_pin()); |
| EXPECT_EQ(usb_pd::PowerRole::kSink, controls_->power_role()); |
| EXPECT_EQ(usb_pd::DataRole::kUpstreamFacingPort, controls_->data_role()); |
| EXPECT_EQ(usb_pd::SpecRevision::kRev2, controls_->spec_revision()); |
| } |
| |
| TEST_F(Fusb302ControlsTest, ConfigureAllRolesSinkOnCc2AllWrites) { |
| // The read values have all the documented bits set. Power's read value is |
| // zero, because the tested method sets all the documented bits, and we want |
| // to see it changing the register. Reset's read value is zero, because we |
| // only flip bits 0->1 there. |
| mock_i2c_.ExpectWrite({kControl2Address}).ExpectReadStop({0xef}); |
| mock_i2c_.ExpectWriteStop({kControl2Address, 0x22}); |
| mock_i2c_.ExpectWriteStop({kResetAddress, 0x02}); |
| mock_i2c_.ExpectWrite({kSwitches0Address}).ExpectReadStop({0xff}); |
| mock_i2c_.ExpectWriteStop({kSwitches0Address, 0x0b}); |
| mock_i2c_.ExpectWrite({kSwitches1Address}).ExpectReadStop({0xf7}); |
| mock_i2c_.ExpectWriteStop({kSwitches1Address, 0x26}); |
| mock_i2c_.ExpectWrite({kPowerAddress}).ExpectReadStop({0x00}); |
| mock_i2c_.ExpectWriteStop({kPowerAddress, 0x0f}); |
| mock_i2c_.ExpectWrite({kControl0Address}).ExpectReadStop({0x6f}); |
| mock_i2c_.ExpectWriteStop({kControl0Address, 0x40}); |
| mock_i2c_.ExpectWrite({kControl1Address}).ExpectReadStop({0x77}); |
| mock_i2c_.ExpectWriteStop({kControl1Address, 0x04}); |
| mock_i2c_.ExpectWrite({kControl3Address}).ExpectReadStop({0x7f}); |
| mock_i2c_.ExpectWriteStop({kControl3Address, 0x07}); |
| mock_i2c_.ExpectWrite({kControl4Address}).ExpectReadStop({0x01}); |
| mock_i2c_.ExpectWriteStop({kControl4Address, 0x00}); |
| mock_i2c_.ExpectWrite({kMeasureAddress}).ExpectReadStop({0x7f}); |
| mock_i2c_.ExpectWriteStop({kMeasureAddress, 0x30}); |
| |
| EXPECT_OK(controls_->ConfigureAllRoles( |
| usb_pd::ConfigChannelPinSwitch::kCc2, usb_pd::PowerRole::kSink, |
| usb_pd::DataRole::kUpstreamFacingPort, usb_pd::SpecRevision::kRev2)); |
| |
| EXPECT_EQ(usb_pd::ConfigChannelPinSwitch::kCc2, controls_->wired_cc_pin()); |
| EXPECT_EQ(usb_pd::PowerRole::kSink, controls_->power_role()); |
| EXPECT_EQ(usb_pd::DataRole::kUpstreamFacingPort, controls_->data_role()); |
| EXPECT_EQ(usb_pd::SpecRevision::kRev2, controls_->spec_revision()); |
| } |
| |
| } // namespace |
| |
| } // namespace fusb302 |