blob: beaa2c8832e815cd94312527fa6f9c125ad6126b [file] [log] [blame]
// Copyright 2021 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_FUSB302_FUSB302_H_
#define SRC_DEVICES_POWER_DRIVERS_FUSB302_FUSB302_H_
#include <fidl/fuchsia.hardware.i2c/cpp/wire.h>
#include <fidl/fuchsia.hardware.powersource/cpp/wire.h>
#include <lib/async/cpp/irq.h>
#include <lib/async/cpp/wait.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/devfs/cpp/connector.h>
#include <lib/inspect/cpp/inspector.h>
#include <lib/zx/interrupt.h>
#include <lib/zx/result.h>
#include <lib/zx/timer.h>
#include <threads.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include "lib/fdf/cpp/dispatcher.h"
#include "src/devices/power/drivers/fusb302/fusb302-controls.h"
#include "src/devices/power/drivers/fusb302/fusb302-fifos.h"
#include "src/devices/power/drivers/fusb302/fusb302-identity.h"
#include "src/devices/power/drivers/fusb302/fusb302-protocol.h"
#include "src/devices/power/drivers/fusb302/fusb302-sensors.h"
#include "src/devices/power/drivers/fusb302/fusb302-signals.h"
#include "src/devices/power/drivers/fusb302/pd-sink-state-machine.h"
#include "src/devices/power/drivers/fusb302/typec-port-state-machine.h"
#include "src/devices/power/drivers/fusb302/usb-pd-sink-policy.h"
namespace fusb302 {
// Fusb302: Device that keeps track of the state of the HW, services FIDL requests, and runs the IRQ
// thread, which in turn runs StateMachine when called on.
class Fusb302 : public fidl::WireServer<fuchsia_hardware_powersource::Source> {
public:
Fusb302(fdf::Dispatcher dispatcher, fidl::ClientEnd<fuchsia_hardware_i2c::Device> i2c,
zx::interrupt irq)
: dispatcher_(std::move(dispatcher)),
i2c_(std::move(i2c)),
irq_(std::move(irq)),
identity_(i2c_, inspect_.GetRoot().CreateChild("Identity")),
sensors_(i2c_, inspect_.GetRoot().CreateChild("Sensors")),
fifos_(i2c_),
// GoodCrcGenerationMode::kSoftware is not fast enough for meeting the
// reaction time mandated by the USB PD specification.
protocol_(GoodCrcGenerationMode::kAssumed, fifos_),
signals_(i2c_, sensors_, protocol_),
controls_(i2c_, sensors_, inspect_.GetRoot().CreateChild("Controls")),
sink_policy_({.min_voltage_mv = 5'000, .max_voltage_mv = 12'000, .max_power_mw = 24'000}),
port_state_machine_(*this, inspect_.GetRoot().CreateChild("PortStateMachine")),
pd_state_machine_(sink_policy_, *this,
inspect_.GetRoot().CreateChild("SinkPolicyEngineStateMachine")) {
ZX_DEBUG_ASSERT(i2c_.is_valid());
ZX_DEBUG_ASSERT(irq_.is_valid());
}
Fusb302(const Fusb302&) = delete;
Fusb302& operator=(const Fusb302&) = delete;
~Fusb302() override {
irq_handler_.Cancel();
const zx_status_t status = irq_.destroy();
if (status != ZX_OK) {
FDF_LOG(WARNING, "zx::interrupt::destroy() failed: %s", zx_status_get_string(status));
}
timeout_handler_.Cancel();
}
// Initialization Functions and Variables
zx_status_t Init();
// TODO(rdzhuang): change power FIDL to supply required values in SourceInfo
void GetPowerInfo(GetPowerInfoCompleter::Sync& completer) override {
// For now, we hardcode this value. When we support other power types in the future, this will
// need to vary depending on selected source capability.
completer.Reply(ZX_OK, {.type = fuchsia_hardware_powersource::PowerType::kAc,
.state = fuchsia_hardware_powersource::wire::kPowerStateCharging});
}
void GetStateChangeEvent(GetStateChangeEventCompleter::Sync& completer) override {
completer.Reply(ZX_ERR_NOT_SUPPORTED, {});
}
void GetBatteryInfo(GetBatteryInfoCompleter::Sync& completer) override {
completer.Reply(ZX_ERR_NOT_SUPPORTED, {});
}
Fusb302Sensors& sensors() { return sensors_; }
Fusb302Protocol& protocol() { return protocol_; }
Fusb302Controls& controls() { return controls_; }
inspect::Inspector& InspectorForTesting() { return inspect_; }
// Asynchronously waits for a timer to be signaled once.
//
// When the timer is signaled, the state machines connected to this instance
// will be run with an indication that a timer was signaled.
zx::result<> WaitAsyncForTimer(zx::timer& timer);
private:
zx_status_t ResetHardwareAndStartPowerRoleDetection();
void HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq, zx_status_t status,
const zx_packet_interrupt_t* interrupt);
void HandleTimeout(async_dispatcher_t*, async::WaitBase*, zx_status_t status,
const zx_packet_signal_t*);
void ProcessStateChanges(HardwareStateChanges changes);
fdf::Dispatcher dispatcher_;
fidl::ClientEnd<fuchsia_hardware_i2c::Device> i2c_;
zx::interrupt irq_;
async::IrqMethod<Fusb302, &Fusb302::HandleIrq> irq_handler_{this};
async::WaitOnce timeout_handler_;
inspect::Inspector inspect_;
Fusb302Identity identity_;
Fusb302Sensors sensors_;
Fusb302Fifos fifos_;
Fusb302Protocol protocol_;
Fusb302Signals signals_;
Fusb302Controls controls_;
usb_pd::SinkPolicy sink_policy_;
TypeCPortStateMachine port_state_machine_;
SinkPolicyEngineStateMachine pd_state_machine_;
};
constexpr char kDeviceName[] = "fusb302";
class Fusb302Device : public fdf::DriverBase {
public:
Fusb302Device(fdf::DriverStartArgs start_args,
fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: fdf::DriverBase(kDeviceName, std::move(start_args), std::move(driver_dispatcher)),
devfs_connector_(fit::bind_member<&Fusb302Device::Serve>(this)) {}
zx::result<> Start() override;
void Stop() override;
private:
zx::result<> CreateDevfsNode();
void Serve(fidl::ServerEnd<fuchsia_hardware_powersource::Source> server) {
source_bindings_.AddBinding(dispatcher(), std::move(server), device_.get(),
fidl::kIgnoreBindingClosure);
}
std::unique_ptr<Fusb302> device_;
fidl::ServerBindingGroup<fuchsia_hardware_powersource::Source> source_bindings_;
fidl::WireSyncClient<fuchsia_driver_framework::Node> node_;
fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
driver_devfs::Connector<fuchsia_hardware_powersource::Source> devfs_connector_;
};
} // namespace fusb302
#endif // SRC_DEVICES_POWER_DRIVERS_FUSB302_FUSB302_H_