| // 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_GOODIX_GT92XX_H_ |
| #define SRC_UI_INPUT_DRIVERS_GOODIX_GT92XX_H_ |
| |
| #include <fidl/fuchsia.hardware.gpio/cpp/wire.h> |
| #include <fidl/fuchsia.input.report/cpp/wire.h> |
| #include <lib/ddk/device.h> |
| #include <lib/device-protocol/i2c-channel.h> |
| #include <lib/fzl/vmo-mapper.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/types.h> |
| |
| #include <atomic> |
| #include <utility> |
| |
| #include <ddktl/device.h> |
| #include <ddktl/protocol/empty-protocol.h> |
| #include <fbl/mutex.h> |
| #include <fbl/vector.h> |
| |
| // clang-format off |
| #define GT_REG_DSP_CONTROL 0x4010 |
| #define GT_REG_SRAM_BANK 0x4048 |
| #define GT_REG_MEM_CD_ENABLE 0x4049 |
| #define GT_REG_CACHE_ENABLE 0x404b |
| #define GT_REG_TIMER0_ENABLE 0x40b0 |
| #define GT_REG_SW_RESET 0x4180 |
| #define GT_HOLD_SS51 0b0100 |
| #define GT_HOLD_DSP 0b1000 |
| #define GT_REG_CPU_RESET 0x4184 |
| #define GT_REG_BOOTCONTROL_B0 0x4190 |
| #define GT_REG_BOOT_OPTION_B0 0x4218 |
| |
| #define GT_REG_FW_MESSAGE 0x41e4 |
| #define GT_REG_FW_MESSAGE_RETRIES 3 |
| |
| #define GT_REG_HW_INFO 0x4220 |
| #define GT_REG_BOOT_CONTROL 0x5094 |
| |
| #define GT_REG_SLEEP 0x8040 |
| #define GT_REG_CONFIG_DATA 0x8047 |
| #define GT_REG_MAX_X_LO 0x8048 |
| #define GT_REG_MAX_X_HI 0x8049 |
| #define GT_REG_MAX_Y_LO 0x804a |
| #define GT_REG_MAX_Y_HI 0x804b |
| #define GT_REG_NUM_FINGERS 0x804c |
| |
| #define GT_REG_CONFIG_REFRESH 0x812a |
| #define GT_REG_PRODUCT_INFO 0x8140 |
| #define GT_REG_FW_VERSION 0x8144 |
| #define GT_REG_SENSOR_ID 0x814a |
| #define GT_REG_TOUCH_STATUS 0x814e |
| #define GT_REG_REPORTS 0x814f |
| |
| #define GT_REG_FIRMWARE 0x41e4 |
| #define GT_FIRMWARE_MAGIC 0xbe |
| |
| #define GT_REG_TOUCH_STATUS_READY 0x80 |
| // clang-format on |
| |
| namespace goodix { |
| |
| class Gt92xxDevice; |
| using DeviceType = |
| ddk::Device<Gt92xxDevice, ddk::Messageable<fuchsia_input_report::InputDevice>::Mixin, |
| ddk::Unbindable>; |
| |
| class Gt92xxDevice : public DeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_INPUTREPORT> { |
| public: |
| struct SectionInfo { |
| uint16_t address; |
| uint8_t sram_bank; |
| uint8_t copy_command; |
| }; |
| |
| Gt92xxDevice(zx_device_t* device, async_dispatcher_t* dispatcher, ddk::I2cChannel i2c, |
| fidl::ClientEnd<fuchsia_hardware_gpio::Gpio> intr, |
| fidl::ClientEnd<fuchsia_hardware_gpio::Gpio> reset) |
| : DeviceType(device), |
| dispatcher_(dispatcher), |
| i2c_(std::move(i2c)), |
| int_gpio_(std::move(intr)), |
| reset_gpio_(std::move(reset)) {} |
| |
| static fbl::Vector<uint8_t> GetConfData(); |
| |
| static zx_status_t Create(zx_device_t* device); |
| |
| void DdkRelease(); |
| void DdkUnbind(ddk::UnbindTxn txn); |
| |
| // fuchsia_input_report::InputDevice required methods |
| 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); |
| } |
| |
| protected: |
| zx_status_t Init(); |
| std::atomic<bool> running_; |
| zx::interrupt irq_; |
| int Thread(); |
| |
| private: |
| static constexpr size_t kFeatureAndDescriptorBufferSize = 512; |
| |
| static constexpr uint32_t kMaxPoints = 5; |
| |
| struct GtInputReport { |
| 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); |
| }; |
| |
| static constexpr int kI2cRetries = 5; |
| |
| static bool ProductIdsMatch(const uint8_t* firmware_product_id, const uint8_t* chip_product_id); |
| |
| zx_status_t ShutDown(); |
| |
| void LogFirmwareStatus(); |
| |
| // performs hardware reset using gpio |
| zx_status_t HWReset(); |
| |
| zx_status_t SetSramBank(uint8_t bank) { return Write(GT_REG_SRAM_BANK, bank); } |
| |
| zx_status_t EnableCodeAccess() { return Write(GT_REG_MEM_CD_ENABLE, 1); } |
| zx_status_t DisableCodeAccess() { return Write(GT_REG_MEM_CD_ENABLE, 0); } |
| |
| zx_status_t DisableCache() { return Write(GT_REG_CACHE_ENABLE, 0); } |
| |
| zx_status_t DisableWdt() { return Write(GT_REG_TIMER0_ENABLE, 0); } |
| |
| zx_status_t HoldSs51AndDsp() { return Write(GT_REG_SW_RESET, GT_HOLD_SS51 | GT_HOLD_DSP); } |
| zx_status_t HoldSs51ReleaseDsp() { return Write(GT_REG_SW_RESET, GT_HOLD_SS51); } |
| zx_status_t ReleaseSs51HoldDsp() { return Write(GT_REG_SW_RESET, GT_HOLD_DSP); } |
| zx_status_t ReleaseSs51AndDsp() { return Write(GT_REG_SW_RESET, 0); } |
| zx::result<bool> Ss51AndDspHeld() { |
| auto status = Read(GT_REG_SW_RESET); |
| if (status.is_ok()) { |
| return zx::ok(status.value() == (GT_HOLD_SS51 | GT_HOLD_DSP)); |
| } |
| return status.take_error(); |
| } |
| |
| zx_status_t TriggerSoftwareReset() { return Write(GT_REG_CPU_RESET, 1); } |
| |
| zx_status_t SetBootFromSram() { return Write(GT_REG_BOOTCONTROL_B0, 0b10); } |
| |
| zx_status_t SetScramble() { return Write(GT_REG_BOOT_OPTION_B0, 0); } |
| |
| zx_status_t WriteCopyCommand(uint8_t command) { return Write(GT_REG_BOOT_CONTROL, command); } |
| zx::result<bool> DeviceBusy() { |
| auto status = Read(GT_REG_BOOT_CONTROL); |
| if (status.is_ok()) { |
| return zx::ok(status.value() != 0); |
| } |
| return status.take_error(); |
| } |
| |
| zx::result<fzl::VmoMapper> LoadAndVerifyFirmware(); |
| bool IsFirmwareApplicable(const fzl::VmoMapper& firmware_mapper); |
| zx_status_t EnterUpdateMode(); |
| zx_status_t LeaveUpdateMode(); |
| zx_status_t WritePayload(uint16_t address, cpp20::span<const uint8_t> data); |
| zx_status_t VerifyPayload(uint16_t address, cpp20::span<const uint8_t> data); |
| zx_status_t WaitUntilNotBusy(); |
| zx_status_t WriteDspIsp(cpp20::span<const uint8_t> dsp_isp); |
| zx_status_t WriteGwakeOrLinkSection(SectionInfo section_info, cpp20::span<const uint8_t> section); |
| zx_status_t WriteGwake(cpp20::span<const uint8_t> section); |
| zx_status_t WriteSs51Section(uint8_t section_number, cpp20::span<const uint8_t> section); |
| zx_status_t WriteSs51(cpp20::span<const uint8_t> section); |
| zx_status_t WriteDsp(cpp20::span<const uint8_t> section); |
| zx_status_t WriteBootOrBootIsp(SectionInfo section_info, cpp20::span<const uint8_t> section); |
| zx_status_t WriteBoot(cpp20::span<const uint8_t> section); |
| zx_status_t WriteBootIsp(cpp20::span<const uint8_t> section); |
| zx_status_t WriteLink(cpp20::span<const uint8_t> section); |
| zx_status_t WriteLinkSection(uint8_t section_number, cpp20::span<const uint8_t> section); |
| |
| zx_status_t UpdateFirmwareIfNeeded(); |
| |
| zx::result<uint8_t> Read(uint16_t addr); |
| zx_status_t Read(uint16_t addr, uint8_t* buf, size_t len); |
| zx_status_t Write(uint16_t addr, uint8_t val); |
| zx_status_t Write(uint8_t* buf, size_t len); |
| |
| async_dispatcher_t* dispatcher_; |
| |
| ddk::I2cChannel i2c_; |
| fidl::WireSyncClient<fuchsia_hardware_gpio::Gpio> int_gpio_; |
| fidl::WireSyncClient<fuchsia_hardware_gpio::Gpio> reset_gpio_; |
| |
| thrd_t thread_; |
| input_report_reader::InputReportReaderManager<GtInputReport> readers_; |
| |
| 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_ = {}; |
| |
| enum { |
| kNoFirmware = 0, // No firmware file was supplied |
| kInternalError, // An internal error was encountered when loading the firmware |
| kFirmwareInvalid, // The firmware file is corrupt or invalid |
| kFirmwareNotApplicable, // The supplied firmware is not applicable to the chip |
| kChipFirmwareCurrent, // The chip firmware is already at the latest version |
| kFirmwareUpdateError, // The chip did something unexpected, or there was an error on the bus |
| kFirmwareUpdated, // The firmware updated completed successfully |
| kFirmwareStatusCount, |
| } firmware_status_ = kFirmwareUpdateError; |
| }; |
| } // namespace goodix |
| |
| #endif // SRC_UI_INPUT_DRIVERS_GOODIX_GT92XX_H_ |