| // 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. |
| |
| #ifndef SRC_UI_INPUT_DRIVERS_FOCALTECH_FT_DEVICE_H_ |
| #define SRC_UI_INPUT_DRIVERS_FOCALTECH_FT_DEVICE_H_ |
| |
| #include <fidl/fuchsia.hardware.gpio/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.input.focaltech/cpp/fidl.h> |
| #include <fidl/fuchsia.input.report/cpp/wire.h> |
| #include <lib/async/cpp/irq.h> |
| #include <lib/device-protocol/display-panel.h> |
| #include <lib/driver/component/cpp/driver_base.h> |
| #include <lib/driver/devfs/cpp/connector.h> |
| #include <lib/input_report_reader/reader.h> |
| #include <lib/inspect/cpp/inspect.h> |
| #include <lib/stdcompat/span.h> |
| #include <lib/zx/interrupt.h> |
| #include <lib/zx/result.h> |
| #include <threads.h> |
| #include <zircon/compiler.h> |
| #include <zircon/types.h> |
| |
| #include <fbl/mutex.h> |
| |
| #include "src/devices/i2c/lib/i2c-channel/i2c-channel.h" |
| |
| // clang-format off |
| #define FTS_REG_CURPOINT 0x02 |
| #define FTS_REG_FINGER_START 0x03 |
| #define FTS_REG_INT_CNT 0x8F |
| #define FTS_REG_FLOW_WORK_CNT 0x91 |
| #define FTS_REG_WORKMODE 0x00 |
| #define FTS_REG_WORKMODE_FACTORY_VALUE 0x40 |
| #define FTS_REG_WORKMODE_WORK_VALUE 0x00 |
| #define FTS_REG_ESDCHECK_DISABLE 0x8D |
| #define FTS_REG_CHIP_ID 0xA3 |
| #define FTS_REG_CHIP_ID2 0x9F |
| #define FTS_REG_POWER_MODE 0xA5 |
| #define FTS_REG_POWER_MODE_SLEEP_VALUE 0x03 |
| #define FTS_REG_FW_VER 0xA6 |
| #define FTS_REG_VENDOR_ID 0xA8 |
| #define FTS_REG_LCD_BUSY_NUM 0xAB |
| #define FTS_REG_FACE_DEC_MODE_EN 0xB0 |
| #define FTS_REG_FACE_DEC_MODE_STATUS 0x01 |
| #define FTS_REG_IDE_PARA_VER_ID 0xB5 |
| #define FTS_REG_IDE_PARA_STATUS 0xB6 |
| #define FTS_REG_GLOVE_MODE_EN 0xC0 |
| #define FTS_REG_COVER_MODE_EN 0xC1 |
| #define FTS_REG_CHARGER_MODE_EN 0x8B |
| #define FTS_REG_GESTURE_EN 0xD0 |
| #define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3 |
| #define FTS_REG_MODULE_ID 0xE3 |
| #define FTS_REG_LIC_VER 0xE4 |
| #define FTS_REG_ESD_SATURATE 0xED |
| #define FTS_REG_TYPE 0xA0 // Chip model number (refer to datasheet) |
| #define FTS_REG_FIRMID 0xA6 // Firmware version |
| #define FTS_REG_VENDOR_ID 0xA8 |
| #define FTS_REG_PANEL_ID 0xAC |
| #define FTS_REG_RELEASE_ID_HIGH 0xAE // Firmware release ID (two bytes) |
| #define FTS_REG_RELEASE_ID_LOW 0xAF |
| #define FTS_REG_IC_VERSION 0xB1 |
| // clang-format on |
| |
| namespace ft { |
| |
| class FtDevice : public fdf::DriverBase, |
| public fidl::WireServer<fuchsia_input_report::InputDevice> { |
| public: |
| static constexpr std::string_view kDriverName = "focaltech_touch"; |
| static constexpr std::string_view kChildNodeName = "focaltouch-HidDevice"; |
| |
| FtDevice(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher) |
| : DriverBase(kDriverName, std::move(start_args), std::move(driver_dispatcher)) {} |
| |
| // fdf::DriverBase implementation. |
| zx::result<> Start() override; |
| |
| // fidl::WireServer<fuchsia_input_report::InputDevice> implementation. |
| void GetInputReportsReader(GetInputReportsReaderRequestView request, |
| GetInputReportsReaderCompleter::Sync& completer) override; |
| void GetDescriptor(GetDescriptorCompleter::Sync& completer) override; |
| void SendOutputReport(SendOutputReportRequestView request, |
| SendOutputReportCompleter::Sync& completer) override { |
| completer.ReplyError(ZX_ERR_NOT_SUPPORTED); |
| } |
| void GetFeatureReport(GetFeatureReportCompleter::Sync& completer) override { |
| completer.ReplyError(ZX_ERR_NOT_SUPPORTED); |
| } |
| void SetFeatureReport(SetFeatureReportRequestView request, |
| SetFeatureReportCompleter::Sync& completer) override { |
| completer.ReplyError(ZX_ERR_NOT_SUPPORTED); |
| } |
| void GetInputReport(GetInputReportRequestView request, |
| GetInputReportCompleter::Sync& completer) override { |
| completer.ReplyError(ZX_ERR_NOT_SUPPORTED); |
| } |
| void handle_unknown_method( |
| fidl::UnknownMethodMetadata<fuchsia_input_report::InputDevice> metadata, |
| fidl::UnknownMethodCompleter::Sync& completer) override { |
| fdf::warn("Unexpected fidl method invoked: {}", metadata.method_ordinal); |
| } |
| |
| private: |
| static constexpr size_t kFeatureAndDescriptorBufferSize = 512; |
| |
| /* Note: the focaltouch device is connected via i2c and is NOT a HID |
| device. This driver reads a collection of data from the data and |
| parses it into a message which will be sent up the stack. This message |
| complies with a HID descriptor that manually scripted (i.e. - not |
| reported by the device iteself). |
| */ |
| // Number of touch points this device can report simultaneously |
| static constexpr uint32_t kMaxPoints = 10; |
| // Size of each individual touch record (note: there are kMaxPoints of |
| // them) on the i2c bus. This is not the HID report size. |
| static constexpr uint32_t kFingerRptSize = 6; |
| |
| static constexpr size_t kMaxI2cTransferLength = 8; |
| |
| struct FtInputReport { |
| zx::time event_time = zx::time(ZX_TIME_INFINITE_PAST); |
| uint8_t contact_count; |
| struct Contact { |
| uint8_t finger_id; |
| uint16_t x; |
| uint16_t y; |
| }; |
| std::array<Contact, kMaxPoints> contacts; |
| |
| void ToFidlInputReport( |
| fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report, |
| fidl::AnyArena& allocator) const; |
| }; |
| |
| static uint8_t CalculateEcc(std::span<const uint8_t> buffer, uint8_t initial = 0); |
| |
| // Enters romboot and returns true if firmware download is needed, returns false otherwise. |
| zx::result<bool> CheckFirmwareAndStartRomboot(uint8_t firmware_version); |
| zx::result<> StartRomboot(); |
| zx_status_t WaitForRomboot(); |
| |
| zx::result<uint16_t> GetBootId(); |
| |
| // Returns true if the expected value was read before the timeout, false if not. |
| zx::result<bool> WaitForFlashStatus(uint16_t expected_value, int tries, zx::duration retry_sleep); |
| |
| zx::result<> EraseFlash(size_t firmware_size); |
| zx::result<> SendFirmware(cpp20::span<const uint8_t> firmware); |
| zx::result<> SendFirmwarePacket(uint32_t address, std::span<const uint8_t> packet); |
| zx::result<> CheckFirmwareEcc(size_t size, uint8_t expected_ecc); |
| |
| zx::result<uint8_t> ReadReg8(uint8_t address); |
| zx::result<uint16_t> ReadReg16(uint8_t address); |
| |
| zx::result<> Write8(uint8_t value); |
| zx::result<> WriteReg8(uint8_t address, uint8_t value); |
| zx::result<> WriteReg16(uint8_t address, uint16_t value); |
| |
| zx::result<uint8_t> Read(uint8_t addr); |
| zx::result<> Read(uint8_t addr, std::span<uint8_t> dst); |
| |
| void HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq, zx_status_t status, |
| const zx_packet_interrupt_t* interrupt); |
| |
| static FtInputReport ParseReport(std::span<const uint8_t> buf); |
| |
| void LogRegisterValue(uint8_t addr, std::string_view name); |
| |
| zx_status_t UpdateFirmwareIfNeeded(const fuchsia_hardware_input_focaltech::Metadata& metadata, |
| display::PanelType panel_type); |
| |
| void DevfsConnect(fidl::ServerEnd<fuchsia_input_report::InputDevice> server); |
| |
| fidl::WireSyncClient<fuchsia_hardware_gpio::Gpio> int_gpio_; |
| fidl::WireSyncClient<fuchsia_hardware_gpio::Gpio> reset_gpio_; |
| zx::interrupt irq_; |
| async::IrqMethod<FtDevice, &FtDevice::HandleIrq> irq_handler_{this}; |
| i2c::I2cChannel i2c_; |
| |
| inspect::Inspector inspector_; |
| inspect::Node node_; |
| inspect::ValueList values_; |
| |
| inspect::Node metrics_root_; |
| inspect::UintProperty average_latency_usecs_; |
| inspect::UintProperty max_latency_usecs_; |
| inspect::UintProperty total_report_count_; |
| inspect::UintProperty last_event_timestamp_; |
| |
| uint64_t report_count_ = 0; |
| zx::duration total_latency_; |
| zx::duration max_latency_; |
| |
| input_report_reader::InputReportReaderManager<FtInputReport> readers_; |
| uint32_t x_max_; |
| uint32_t y_max_; |
| |
| fidl::ServerBindingGroup<fuchsia_input_report::InputDevice> bindings_; |
| driver_devfs::Connector<fuchsia_input_report::InputDevice> devfs_connector_{ |
| fit::bind_member<&FtDevice::DevfsConnect>(this)}; |
| fdf::OwnedChildNode child_; |
| }; |
| } // namespace ft |
| |
| #endif // SRC_UI_INPUT_DRIVERS_FOCALTECH_FT_DEVICE_H_ |