1/* 2 * Copyright (c) 2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> and was subsequently ported, 6 * modified and enhanced for FreeBSD by Michael Gmelin <freebsd@grem.de>. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 20 unchanged lines hidden (view full) --- 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <sys/cdefs.h> |
37__FBSDID("$FreeBSD: stable/11/sys/dev/cyapa/cyapa.c 310072 2016-12-14 16:27:28Z avg $"); |
38 39/* 40 * CYAPA - Cypress APA trackpad with I2C Interface driver 41 * 42 * Based on DragonFlyBSD's cyapa driver, which referenced the linux 43 * cyapa.c driver to figure out the bootstrapping and commands. 44 * 45 * Unable to locate any datasheet for the device. --- 71 unchanged lines hidden (view full) --- 117#include <sys/selinfo.h> 118#include <sys/sysctl.h> 119#include <sys/sysctl.h> 120#include <sys/systm.h> 121#include <sys/systm.h> 122#include <sys/uio.h> 123#include <sys/vnode.h> 124 |
125#include <dev/iicbus/iiconf.h> 126#include <dev/iicbus/iicbus.h> |
127#include <dev/cyapa/cyapa.h> 128 |
129#include "iicbus_if.h" |
130#include "bus_if.h" 131#include "device_if.h" 132 133#define CYAPA_BUFSIZE 128 /* power of 2 */ 134#define CYAPA_BUFMASK (CYAPA_BUFSIZE - 1) 135 136#define ZSCALE 15 137 --- 6 unchanged lines hidden (view full) --- 144 int rindex; 145 int windex; 146 char buf[CYAPA_BUFSIZE]; 147}; 148 149struct cyapa_softc { 150 device_t dev; 151 int count; /* >0 if device opened */ |
152 struct cdev *devnode; 153 struct selinfo selinfo; 154 struct mtx mutex; 155 156 int cap_resx; 157 int cap_resy; 158 int cap_phyx; 159 int cap_phyy; --- 107 unchanged lines hidden (view full) --- 267 268static int cyapa_debug = 0; 269SYSCTL_INT(_debug, OID_AUTO, cyapa_debug, CTLFLAG_RW, 270 &cyapa_debug, 0, "Enable debugging"); 271static int cyapa_reset = 0; 272SYSCTL_INT(_debug, OID_AUTO, cyapa_reset, CTLFLAG_RW, 273 &cyapa_reset, 0, "Reset track pad"); 274 |
275static int 276cyapa_read_bytes(device_t dev, uint8_t reg, uint8_t *val, int cnt) 277{ 278 uint16_t addr = iicbus_get_addr(dev); 279 struct iic_msg msgs[] = { 280 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 281 { addr, IIC_M_RD, cnt, val }, 282 }; 283 284 return (iicbus_transfer(dev, msgs, nitems(msgs))); 285} 286 287static int 288cyapa_write_bytes(device_t dev, uint8_t reg, const uint8_t *val, int cnt) 289{ 290 uint16_t addr = iicbus_get_addr(dev); 291 struct iic_msg msgs[] = { 292 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 293 { addr, IIC_M_WR | IIC_M_NOSTART, cnt, __DECONST(uint8_t *, val) }, 294 }; 295 296 return (iicbus_transfer(dev, msgs, nitems(msgs))); 297} 298 |
299static void 300cyapa_lock(struct cyapa_softc *sc) 301{ 302 303 mtx_lock(&sc->mutex); 304} 305 306static void --- 29 unchanged lines hidden (view full) --- 336 } 337 } 338} 339 340/* 341 * Initialize the device 342 */ 343static int |
344init_device(device_t dev, struct cyapa_cap *cap, int probe) |
345{ 346 static char bl_exit[] = { 347 0x00, 0xff, 0xa5, 0x00, 0x01, 348 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; 349 static char bl_deactivate[] = { 350 0x00, 0xff, 0x3b, 0x00, 0x01, 351 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; |
352 struct cyapa_boot_regs boot; 353 int error; 354 int retries; 355 |
356 /* Get status */ |
357 error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, 358 (void *)&boot, sizeof(boot)); |
359 if (error) 360 goto done; 361 362 /* 363 * Bootstrap the device if necessary. It can take up to 2 seconds 364 * for the device to fully initialize. 365 */ 366 retries = 20; 367 while ((boot.stat & CYAPA_STAT_RUNNING) == 0 && retries > 0) { 368 if (boot.boot & CYAPA_BOOT_BUSY) { 369 /* Busy, wait loop. */ 370 } else if (boot.error & CYAPA_ERROR_BOOTLOADER) { 371 /* Magic */ |
372 error = cyapa_write_bytes(dev, CMD_BOOT_STATUS, 373 bl_deactivate, sizeof(bl_deactivate)); |
374 if (error) 375 goto done; 376 } else { 377 /* Magic */ |
378 error = cyapa_write_bytes(dev, CMD_BOOT_STATUS, 379 bl_exit, sizeof(bl_exit)); |
380 if (error) 381 goto done; 382 } 383 pause("cyapab1", (hz * 2) / 10); 384 --retries; |
385 error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, 386 (void *)&boot, sizeof(boot)); |
387 if (error) 388 goto done; 389 } 390 391 if (retries == 0) { 392 device_printf(dev, "Unable to bring device out of bootstrap\n"); 393 error = ENXIO; 394 goto done; 395 } 396 397 /* Check identity */ 398 if (cap) { |
399 error = cyapa_read_bytes(dev, CMD_QUERY_CAPABILITIES, 400 (void *)cap, sizeof(*cap)); |
401 402 if (strncmp(cap->prod_ida, "CYTRA", 5) != 0) { 403 device_printf(dev, "Product ID \"%5.5s\" mismatch\n", 404 cap->prod_ida); 405 error = ENXIO; 406 } 407 } |
408 error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, 409 (void *)&boot, sizeof(boot)); |
410 411 if (probe == 0) /* official init */ 412 device_printf(dev, "cyapa init status %02x\n", boot.stat); 413 else if (probe == 2) 414 device_printf(dev, "cyapa reset status %02x\n", boot.stat); 415 416done: 417 if (error) --- 42 unchanged lines hidden (view full) --- 460 461static int 462cyapa_probe(device_t dev) 463{ 464 struct cyapa_cap cap; 465 int addr; 466 int error; 467 |
468 addr = iicbus_get_addr(dev); |
469 470 /* 471 * 0x67 - cypress trackpad on the acer c720 472 * (other devices might use other ids). 473 */ |
474 if (addr != 0xce) |
475 return (ENXIO); 476 |
477 error = init_device(dev, &cap, 1); |
478 if (error != 0) 479 return (ENXIO); 480 481 device_set_desc(dev, "Cypress APA I2C Trackpad"); 482 483 return (BUS_PROBE_VENDOR); 484} 485 --- 4 unchanged lines hidden (view full) --- 490 struct cyapa_cap cap; 491 int unit; 492 int addr; 493 494 sc = device_get_softc(dev); 495 sc->reporting_mode = 1; 496 497 unit = device_get_unit(dev); |
498 addr = iicbus_get_addr(dev); |
499 |
500 if (init_device(dev, &cap, 0)) |
501 return (ENXIO); 502 503 mtx_init(&sc->mutex, "cyapa", NULL, MTX_DEF); 504 505 sc->dev = dev; |
506 507 knlist_init_mtx(&sc->selinfo.si_note, &sc->mutex); 508 509 sc->cap_resx = ((cap.max_abs_xy_high << 4) & 0x0F00) | 510 cap.max_abs_x_low; 511 sc->cap_resy = ((cap.max_abs_xy_high << 8) & 0x0F00) | 512 cap.max_abs_y_low; 513 sc->cap_phyx = ((cap.phy_siz_xy_high << 4) & 0x0F00) | --- 652 unchanged lines hidden (view full) --- 1166/* 1167 * MAJOR SUPPORT FUNCTIONS 1168 */ 1169static void 1170cyapa_poll_thread(void *arg) 1171{ 1172 struct cyapa_softc *sc; 1173 struct cyapa_regs regs; |
1174 device_t bus; /* iicbus */ |
1175 int error; 1176 int freq; 1177 int isidle; 1178 int pstate; 1179 int npstate; 1180 int last_reset; 1181 1182 sc = arg; --- 4 unchanged lines hidden (view full) --- 1187 1188 bus = device_get_parent(sc->dev); 1189 1190 cyapa_lock(sc); 1191 sc->poll_thread_running = 1; 1192 1193 while (!sc->detaching) { 1194 cyapa_unlock(sc); |
1195 error = iicbus_request_bus(bus, sc->dev, IIC_WAIT); |
1196 if (error == 0) { |
1197 error = cyapa_read_bytes(sc->dev, CMD_DEV_STATUS, 1198 (void *)®s, sizeof(regs)); |
1199 if (error == 0) { 1200 isidle = cyapa_raw_input(sc, ®s, freq); 1201 } 1202 1203 /* 1204 * For some reason the device can crap-out. If it 1205 * drops back into bootstrap mode try to reinitialize 1206 * it. 1207 */ 1208 if (cyapa_reset || 1209 ((regs.stat & CYAPA_STAT_RUNNING) == 0 && 1210 (unsigned)(ticks - last_reset) > TIME_TO_RESET)) { 1211 cyapa_reset = 0; 1212 last_reset = ticks; |
1213 init_device(sc->dev, NULL, 2); |
1214 } |
1215 iicbus_release_bus(bus, sc->dev); |
1216 } 1217 pause("cyapw", hz / freq); 1218 ++sc->poll_ticks; 1219 1220 if (sc->count == 0) { 1221 freq = cyapa_idle_freq; 1222 npstate = CMD_POWER_MODE_IDLE; 1223 } else if (isidle) { --- 312 unchanged lines hidden (view full) --- 1536static void 1537cyapa_set_power_mode(struct cyapa_softc *sc, int mode) 1538{ 1539 uint8_t data; 1540 device_t bus; 1541 int error; 1542 1543 bus = device_get_parent(sc->dev); |
1544 error = iicbus_request_bus(bus, sc->dev, IIC_WAIT); |
1545 if (error == 0) { |
1546 error = cyapa_read_bytes(sc->dev, CMD_POWER_MODE, 1547 &data, 1); |
1548 data = (data & ~0xFC) | mode; 1549 if (error == 0) { |
1550 error = cyapa_write_bytes(sc->dev, CMD_POWER_MODE, 1551 &data, 1); |
1552 } |
1553 iicbus_release_bus(bus, sc->dev); |
1554 } 1555} 1556 1557/* 1558 * FIFO FUNCTIONS 1559 */ 1560 1561/* --- 138 unchanged lines hidden (view full) --- 1700 --delta; 1701 ++fuzz; 1702 } 1703 *fuzzp = fuzz; 1704 1705 return (delta); 1706} 1707 |
1708DRIVER_MODULE(cyapa, iicbus, cyapa_driver, cyapa_devclass, NULL, NULL); 1709MODULE_DEPEND(cyapa, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); |
1710MODULE_VERSION(cyapa, 1); |