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