1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddk/binding.h> 6#include <ddk/debug.h> 7#include <ddk/protocol/platform-defs.h> 8#include <ddk/protocol/platform-device.h> 9#include <fbl/auto_call.h> 10#include <fbl/auto_lock.h> 11 12#include "gt92xx.h" 13 14namespace goodix { 15// Configuration data 16// first two bytes contain starting register address (part of i2c transaction) 17static uint8_t conf_data[] = { 18 GT_REG_CONFIG_DATA >> 8, GT_REG_CONFIG_DATA & 0xff, 19 0x5C, 0x00, 0x04, 0x58, 0x02, 0x05, 0xBD, 0xC0, 20 0x00, 0x08, 0x1E, 0x05, 0x50, 0x32, 0x05, 0x0B, 21 0x00, 0x00, 0x00, 0x00, 0x40, 0x12, 0x00, 0x17, 22 0x17, 0x19, 0x12, 0x8D, 0x2D, 0x0F, 0x3F, 0x41, 23 0xB2, 0x04, 0x00, 0x00, 0x00, 0xBC, 0x03, 0x1D, 24 0x1E, 0x80, 0x01, 0x00, 0x14, 0x46, 0x00, 0x00, 25 0x00, 0x00, 0x00, 0x37, 0x55, 0x8F, 0xC5, 0x02, 26 0x07, 0x11, 0x00, 0x04, 0x8A, 0x39, 0x00, 0x81, 27 0x3E, 0x00, 0x78, 0x44, 0x00, 0x71, 0x4A, 0x00, 28 0x6A, 0x51, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x00, 29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 32 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 33 0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0E, 34 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, 0x00, 0x00, 35 0xFF, 0xFF, 0x1F, 0xE7, 0xFF, 0xFF, 0xFF, 0x0F, 36 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x29, 37 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 38 0x20, 0x1F, 0x1E, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 39 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 0x00, 0x00, 0x6C, 0x01}; 48 49int Gt92xxDevice::Thread() { 50 zx_status_t status; 51 zxlogf(INFO, "gt92xx: entering irq thread\n"); 52 while (true) { 53 status = irq_.wait(nullptr); 54 if (!running_.load()) { 55 return ZX_OK; 56 } 57 if (status != ZX_OK) { 58 zxlogf(ERROR, "gt92xx: Interrupt error %d\n", status); 59 } 60 uint8_t touch_stat = Read(GT_REG_TOUCH_STATUS); 61 if (touch_stat & 0x80) { 62 uint8_t num_reports = touch_stat & 0x0f; 63 FingerReport reports[kMaxPoints]; 64 // Read touch reports 65 zx_status_t status = 66 Read(GT_REG_REPORTS, reinterpret_cast<uint8_t*>(&reports), 67 static_cast<uint8_t>(sizeof(FingerReport) * kMaxPoints)); 68 if (status == ZX_OK) { 69 fbl::AutoLock lock(&proxy_lock_); 70 gt_rpt_.rpt_id = GT92XX_RPT_ID_TOUCH; 71 gt_rpt_.contact_count = num_reports; 72 // We are reusing same HID report as ft3x77 to simplify astro integration 73 // so we need to copy from device format to HID structure format 74 for (uint32_t i = 0; i < kMaxPoints; i++) { 75 gt_rpt_.fingers[i].finger_id = reports[i].id; 76 gt_rpt_.fingers[i].x = reports[i].x; 77 gt_rpt_.fingers[i].y = reports[i].y; 78 } 79 if (proxy_.is_valid()) { 80 proxy_.IoQueue(reinterpret_cast<uint8_t*>(>_rpt_), sizeof(gt92xx_touch_t)); 81 } 82 } 83 // Clear the touch status 84 Write(GT_REG_TOUCH_STATUS, 0); 85 } 86 } 87 zxlogf(INFO, "gt92xx: exiting\n"); 88 return 0; 89} 90 91zx_status_t Gt92xxDevice::Create(zx_device_t* device) { 92 93 zxlogf(INFO, "gt92xx: driver started...\n"); 94 95 auto pdev = ddk::Pdev::Create(device); 96 if (!pdev) { 97 zxlogf(ERROR, "%s could not acquire platform device\n", __func__); 98 return ZX_ERR_NO_RESOURCES; 99 } 100 101 auto goodix_dev = fbl::make_unique<Gt92xxDevice>(device, 102 fbl::move(pdev->GetI2cChan(0)), 103 fbl::move(pdev->GetGpio(0)), 104 fbl::move(pdev->GetGpio(1))); 105 106 zx_status_t status = goodix_dev->Init(); 107 if (status != ZX_OK) { 108 zxlogf(ERROR, "Could not initialize gt92xx hardware %d\n", status); 109 return status; 110 } 111 112 auto thunk = [](void* arg) -> int { 113 return reinterpret_cast<Gt92xxDevice*>(arg)->Thread(); 114 }; 115 116 auto cleanup = fbl::MakeAutoCall([&]() { goodix_dev->ShutDown(); }); 117 118 goodix_dev->running_.store(true); 119 int ret = thrd_create_with_name(&goodix_dev->thread_, thunk, 120 goodix_dev.get(), 121 "gt92xx-thread"); 122 ZX_DEBUG_ASSERT(ret == thrd_success); 123 124 status = goodix_dev->DdkAdd("gt92xx HidDevice\n"); 125 if (status != ZX_OK) { 126 zxlogf(ERROR, "gt92xx: Could not create hid device: %d\n", status); 127 return status; 128 } else { 129 zxlogf(INFO, "gt92xx: Added hid device\n"); 130 } 131 132 cleanup.cancel(); 133 134 // device intentionally leaked as it is now held by DevMgr 135 __UNUSED auto ptr = goodix_dev.release(); 136 137 return ZX_OK; 138} 139 140zx_status_t Gt92xxDevice::Init() { 141 // Hardware reset 142 HWReset(); 143 144 uint8_t fw = Read(GT_REG_FIRMWARE); 145 if (fw != GT_FIRMWARE_MAGIC) { 146 zxlogf(ERROR, "Invalid gt92xx firmware configuration!\n"); 147 return ZX_ERR_BAD_STATE; 148 } 149 // Device requires 50ms delay after this check (per datasheet) 150 zx_nanosleep(zx_deadline_after(ZX_MSEC(50))); 151 152 // Configuration data should span specific set of registers 153 // last register has flag to latch in new configuration, second 154 // to last register holds checksum of register values. 155 // Note: first two bytes of conf_data hold the 16-bit register address where 156 // the write will start. 157 ZX_DEBUG_ASSERT((countof(conf_data) - sizeof(uint16_t)) == 158 (GT_REG_CONFIG_REFRESH - GT_REG_CONFIG_DATA + 1)); 159 160 // Write conf data to registers 161 zx_status_t status = i2c_.Transact(conf_data, sizeof(conf_data), NULL, 0); 162 if (status != ZX_OK) { 163 return status; 164 } 165 // Device requires 10ms delay to refresh configuration 166 zx_nanosleep(zx_deadline_after(ZX_MSEC(10))); 167 // Clear touch state in case there were spurious touches registered 168 // during startup 169 Write(GT_REG_TOUCH_STATUS, 0); 170 171 status = int_gpio_.GetInterrupt(ZX_INTERRUPT_MODE_EDGE_HIGH, &irq_); 172 173 return status; 174} 175 176void Gt92xxDevice::HWReset() { 177 // Hardware reset will also set the address of the controller to either 178 // 0x14 0r 0x5d. See the datasheet for explanation of sequence. 179 reset_gpio_.ConfigOut(0); //Make reset pin an output and pull low 180 int_gpio_.ConfigOut(0); //Make interrupt pin an output and pull low 181 182 // Delay for 100us 183 zx_nanosleep(zx_deadline_after(ZX_USEC(100))); 184 185 reset_gpio_.Write(1); // Release the reset 186 zx_nanosleep(zx_deadline_after(ZX_MSEC(5))); 187 int_gpio_.ConfigIn(0); // Make interrupt pin an input again; 188 zx_nanosleep(zx_deadline_after(ZX_MSEC(50))); // Wait for reset to complete 189} 190 191zx_status_t Gt92xxDevice::HidBusQuery(uint32_t options, hid_info_t* info) { 192 if (!info) { 193 return ZX_ERR_INVALID_ARGS; 194 } 195 info->dev_num = 0; 196 info->dev_class = HID_DEV_CLASS_OTHER; 197 info->boot_device = false; 198 199 return ZX_OK; 200} 201 202void Gt92xxDevice::DdkRelease() { 203 delete this; 204} 205 206void Gt92xxDevice::DdkUnbind() { 207 ShutDown(); 208 DdkRemove(); 209} 210 211zx_status_t Gt92xxDevice::ShutDown() { 212 running_.store(false); 213 irq_.destroy(); 214 thrd_join(thread_, NULL); 215 { 216 fbl::AutoLock lock(&proxy_lock_); 217 proxy_.clear(); 218 } 219 return ZX_OK; 220} 221 222zx_status_t Gt92xxDevice::HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len) { 223 224 const uint8_t* desc_ptr; 225 uint8_t* buf; 226 *len = get_gt92xx_report_desc(&desc_ptr); 227 fbl::AllocChecker ac; 228 buf = new (&ac) uint8_t[*len]; 229 if (!ac.check()) { 230 return ZX_ERR_NO_MEMORY; 231 } 232 memcpy(buf, desc_ptr, *len); 233 *data = buf; 234 return ZX_OK; 235} 236 237zx_status_t Gt92xxDevice::HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, 238 size_t len, size_t* out_len) { 239 return ZX_ERR_NOT_SUPPORTED; 240} 241 242zx_status_t Gt92xxDevice::HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, 243 size_t len) { 244 return ZX_ERR_NOT_SUPPORTED; 245} 246 247zx_status_t Gt92xxDevice::HidBusGetIdle(uint8_t rpt_id, uint8_t* duration) { 248 return ZX_ERR_NOT_SUPPORTED; 249} 250 251zx_status_t Gt92xxDevice::HidBusSetIdle(uint8_t rpt_id, uint8_t duration) { 252 return ZX_ERR_NOT_SUPPORTED; 253} 254 255zx_status_t Gt92xxDevice::HidBusGetProtocol(uint8_t* protocol) { 256 return ZX_ERR_NOT_SUPPORTED; 257} 258 259zx_status_t Gt92xxDevice::HidBusSetProtocol(uint8_t protocol) { 260 return ZX_OK; 261} 262 263void Gt92xxDevice::HidBusStop() { 264 fbl::AutoLock lock(&proxy_lock_); 265 proxy_.clear(); 266} 267 268zx_status_t Gt92xxDevice::HidBusStart(ddk::HidBusIfcProxy proxy) { 269 fbl::AutoLock lock(&proxy_lock_); 270 if (proxy_.is_valid()) { 271 zxlogf(ERROR, "gt92xx: Already bound!\n"); 272 return ZX_ERR_ALREADY_BOUND; 273 } else { 274 proxy_ = proxy; 275 zxlogf(INFO, "gt92xx: started\n"); 276 } 277 return ZX_OK; 278} 279 280uint8_t Gt92xxDevice::Read(uint16_t addr) { 281 uint8_t rbuf; 282 Read(addr, &rbuf, 1); 283 return rbuf; 284} 285 286zx_status_t Gt92xxDevice::Read(uint16_t addr, uint8_t* buf, uint8_t len) { 287 uint8_t tbuf[2]; 288 tbuf[0] = static_cast<uint8_t>(addr >> 8); 289 tbuf[1] = static_cast<uint8_t>(addr & 0xff); 290 return i2c_.Transact(tbuf, 2, buf, len); 291} 292 293zx_status_t Gt92xxDevice::Write(uint16_t addr, uint8_t val) { 294 uint8_t tbuf[3]; 295 tbuf[0] = static_cast<uint8_t>(addr >> 8); 296 tbuf[1] = static_cast<uint8_t>(addr & 0xff); 297 tbuf[2] = val; 298 return i2c_.Transact(tbuf, 3, NULL, 0); 299} 300 301} // namespace ft 302 303__BEGIN_CDECLS 304 305zx_status_t gt92xx_bind(void* ctx, zx_device_t* device) { 306 return goodix::Gt92xxDevice::Create(device); 307} 308 309static zx_driver_ops_t gt92xx_driver_ops = { 310 .version = DRIVER_OPS_VERSION, 311 .init = nullptr, 312 .bind = gt92xx_bind, 313 .create = nullptr, 314 .release = nullptr, 315}; 316 317// clang-format off 318ZIRCON_DRIVER_BEGIN(gt92xx, gt92xx_driver_ops, "zircon", "0.1", 3) 319 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_GOOGLE), 320 BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_ASTRO), 321 BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_ASTRO_GOODIXTOUCH), 322ZIRCON_DRIVER_END(gt92xx) 323// clang-format on 324__END_CDECLS 325