Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add Cypress TTSP capacitive multi-touch screen support

Cypress TrueTouch(tm) Standard Product controllers are found in
a wide range of embedded devices. This driver add support for a
variety of TTSP controllers.

Since the hardware is capable of tracking identifiable contacts, multi-touch
protocol type B (stateful) is used to report contact information.

The driver is composed of a core driver that process the data sent by
the contacts and a set of bus specific interface modules. This patch
adds the base core TTSP driver.

Signed-off-by: Javier Martinez Canillas <javier@dowhile0.org>
Reviewed-by: Henrik Rydberg <rydberg@euromail.se>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Javier Martinez Canillas and committed by
Dmitry Torokhov
4065d1e7 31175a83

+1223 -2
+31 -1
drivers/input/touchscreen/Kconfig
··· 139 139 tristate "cy8ctmg110 touchscreen" 140 140 depends on I2C 141 141 depends on GPIOLIB 142 - 143 142 help 144 143 Say Y here if you have a cy8ctmg110 capacitive touchscreen on 145 144 an AAVA device. ··· 147 148 148 149 To compile this driver as a module, choose M here: the 149 150 module will be called cy8ctmg110_ts. 151 + 152 + config TOUCHSCREEN_CYTTSP_CORE 153 + tristate "Cypress TTSP touchscreen" 154 + help 155 + Say Y here if you have a touchscreen using controller from 156 + the Cypress TrueTouch(tm) Standard Product family connected 157 + to your system. You will also need to select appropriate 158 + bus connection below. 159 + 160 + If unsure, say N. 161 + 162 + To compile this driver as a module, choose M here: the 163 + module will be called cyttsp_core. 164 + 165 + config TOUCHSCREEN_CYTTSP_I2C 166 + tristate "support I2C bus connection" 167 + depends on TOUCHSCREEN_CYTTSP_CORE && I2C 168 + help 169 + Say Y here if the touchscreen is connected via I2C bus. 170 + 171 + To compile this driver as a module, choose M here: the 172 + module will be called cyttsp_i2c. 173 + 174 + config TOUCHSCREEN_CYTTSP_SPI 175 + tristate "support SPI bus connection" 176 + depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER 177 + help 178 + Say Y here if the touchscreen is connected via SPI bus. 179 + 180 + To compile this driver as a module, choose M here: the 181 + module will be called cyttsp_spi. 150 182 151 183 config TOUCHSCREEN_DA9034 152 184 tristate "Touchscreen support for Dialog Semiconductor DA9034"
+4 -1
drivers/input/touchscreen/Makefile
··· 16 16 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o 17 17 obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o 18 18 obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o 19 - obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o 19 + obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o 20 20 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o 21 + obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o 22 + obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o 23 + obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o 21 24 obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o 22 25 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o 23 26 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
+625
drivers/input/touchscreen/cyttsp_core.c
··· 1 + /* 2 + * Core Source for: 3 + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers. 4 + * For use with Cypress Txx3xx parts. 5 + * Supported parts include: 6 + * CY8CTST341 7 + * CY8CTMA340 8 + * 9 + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. 10 + * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * version 2, and only version 2, as published by the 15 + * Free Software Foundation. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License along 23 + * with this program; if not, write to the Free Software Foundation, Inc., 24 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 25 + * 26 + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> 27 + * 28 + */ 29 + 30 + #include <linux/delay.h> 31 + #include <linux/input.h> 32 + #include <linux/input/mt.h> 33 + #include <linux/gpio.h> 34 + #include <linux/interrupt.h> 35 + #include <linux/slab.h> 36 + 37 + #include "cyttsp_core.h" 38 + 39 + /* Bootloader number of command keys */ 40 + #define CY_NUM_BL_KEYS 8 41 + 42 + /* helpers */ 43 + #define GET_NUM_TOUCHES(x) ((x) & 0x0F) 44 + #define IS_LARGE_AREA(x) (((x) & 0x10) >> 4) 45 + #define IS_BAD_PKT(x) ((x) & 0x20) 46 + #define IS_VALID_APP(x) ((x) & 0x01) 47 + #define IS_OPERATIONAL_ERR(x) ((x) & 0x3F) 48 + #define GET_HSTMODE(reg) (((reg) & 0x70) >> 4) 49 + #define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4) 50 + 51 + #define CY_REG_BASE 0x00 52 + #define CY_REG_ACT_DIST 0x1E 53 + #define CY_REG_ACT_INTRVL 0x1D 54 + #define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1) 55 + #define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1) 56 + #define CY_MAXZ 255 57 + #define CY_DELAY_DFLT 20 /* ms */ 58 + #define CY_DELAY_MAX 500 59 + #define CY_ACT_DIST_DFLT 0xF8 60 + #define CY_HNDSHK_BIT 0x80 61 + /* device mode bits */ 62 + #define CY_OPERATE_MODE 0x00 63 + #define CY_SYSINFO_MODE 0x10 64 + /* power mode select bits */ 65 + #define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */ 66 + #define CY_DEEP_SLEEP_MODE 0x02 67 + #define CY_LOW_POWER_MODE 0x04 68 + 69 + /* Slots management */ 70 + #define CY_MAX_FINGER 4 71 + #define CY_MAX_ID 16 72 + 73 + static const u8 bl_command[] = { 74 + 0x00, /* file offset */ 75 + 0xFF, /* command */ 76 + 0xA5, /* exit bootloader command */ 77 + 0, 1, 2, 3, 4, 5, 6, 7 /* default keys */ 78 + }; 79 + 80 + static int ttsp_read_block_data(struct cyttsp *ts, u8 command, 81 + u8 length, void *buf) 82 + { 83 + int error; 84 + int tries; 85 + 86 + for (tries = 0; tries < CY_NUM_RETRY; tries++) { 87 + error = ts->bus_ops->read(ts, command, length, buf); 88 + if (!error) 89 + return 0; 90 + 91 + msleep(CY_DELAY_DFLT); 92 + } 93 + 94 + return -EIO; 95 + } 96 + 97 + static int ttsp_write_block_data(struct cyttsp *ts, u8 command, 98 + u8 length, void *buf) 99 + { 100 + int error; 101 + int tries; 102 + 103 + for (tries = 0; tries < CY_NUM_RETRY; tries++) { 104 + error = ts->bus_ops->write(ts, command, length, buf); 105 + if (!error) 106 + return 0; 107 + 108 + msleep(CY_DELAY_DFLT); 109 + } 110 + 111 + return -EIO; 112 + } 113 + 114 + static int ttsp_send_command(struct cyttsp *ts, u8 cmd) 115 + { 116 + return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd); 117 + } 118 + 119 + static int cyttsp_load_bl_regs(struct cyttsp *ts) 120 + { 121 + memset(&ts->bl_data, 0, sizeof(ts->bl_data)); 122 + ts->bl_data.bl_status = 0x10; 123 + 124 + return ttsp_read_block_data(ts, CY_REG_BASE, 125 + sizeof(ts->bl_data), &ts->bl_data); 126 + } 127 + 128 + static int cyttsp_exit_bl_mode(struct cyttsp *ts) 129 + { 130 + int error; 131 + u8 bl_cmd[sizeof(bl_command)]; 132 + 133 + memcpy(bl_cmd, bl_command, sizeof(bl_command)); 134 + if (ts->pdata->bl_keys) 135 + memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS], 136 + ts->pdata->bl_keys, sizeof(bl_command)); 137 + 138 + error = ttsp_write_block_data(ts, CY_REG_BASE, 139 + sizeof(bl_cmd), bl_cmd); 140 + if (error) 141 + return error; 142 + 143 + /* wait for TTSP Device to complete the operation */ 144 + msleep(CY_DELAY_DFLT); 145 + 146 + error = cyttsp_load_bl_regs(ts); 147 + if (error) 148 + return error; 149 + 150 + if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) 151 + return -EIO; 152 + 153 + return 0; 154 + } 155 + 156 + static int cyttsp_set_operational_mode(struct cyttsp *ts) 157 + { 158 + int error; 159 + 160 + error = ttsp_send_command(ts, CY_OPERATE_MODE); 161 + if (error) 162 + return error; 163 + 164 + /* wait for TTSP Device to complete switch to Operational mode */ 165 + error = ttsp_read_block_data(ts, CY_REG_BASE, 166 + sizeof(ts->xy_data), &ts->xy_data); 167 + if (error) 168 + return error; 169 + 170 + return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0; 171 + } 172 + 173 + static int cyttsp_set_sysinfo_mode(struct cyttsp *ts) 174 + { 175 + int error; 176 + 177 + memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data)); 178 + 179 + /* switch to sysinfo mode */ 180 + error = ttsp_send_command(ts, CY_SYSINFO_MODE); 181 + if (error) 182 + return error; 183 + 184 + /* read sysinfo registers */ 185 + msleep(CY_DELAY_DFLT); 186 + error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data), 187 + &ts->sysinfo_data); 188 + if (error) 189 + return error; 190 + 191 + if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl) 192 + return -EIO; 193 + 194 + return 0; 195 + } 196 + 197 + static int cyttsp_set_sysinfo_regs(struct cyttsp *ts) 198 + { 199 + int retval = 0; 200 + 201 + if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT || 202 + ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT || 203 + ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) { 204 + 205 + u8 intrvl_ray[] = { 206 + ts->pdata->act_intrvl, 207 + ts->pdata->tch_tmout, 208 + ts->pdata->lp_intrvl 209 + }; 210 + 211 + /* set intrvl registers */ 212 + retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL, 213 + sizeof(intrvl_ray), intrvl_ray); 214 + msleep(CY_DELAY_DFLT); 215 + } 216 + 217 + return retval; 218 + } 219 + 220 + static int cyttsp_soft_reset(struct cyttsp *ts) 221 + { 222 + unsigned long timeout; 223 + int retval; 224 + 225 + /* wait for interrupt to set ready completion */ 226 + INIT_COMPLETION(ts->bl_ready); 227 + ts->state = CY_BL_STATE; 228 + 229 + enable_irq(ts->irq); 230 + 231 + retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE); 232 + if (retval) 233 + goto out; 234 + 235 + timeout = wait_for_completion_timeout(&ts->bl_ready, 236 + msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX)); 237 + retval = timeout ? 0 : -EIO; 238 + 239 + out: 240 + ts->state = CY_IDLE_STATE; 241 + disable_irq(ts->irq); 242 + return retval; 243 + } 244 + 245 + static int cyttsp_act_dist_setup(struct cyttsp *ts) 246 + { 247 + u8 act_dist_setup = ts->pdata->act_dist; 248 + 249 + /* Init gesture; active distance setup */ 250 + return ttsp_write_block_data(ts, CY_REG_ACT_DIST, 251 + sizeof(act_dist_setup), &act_dist_setup); 252 + } 253 + 254 + static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids) 255 + { 256 + ids[0] = xy_data->touch12_id >> 4; 257 + ids[1] = xy_data->touch12_id & 0xF; 258 + ids[2] = xy_data->touch34_id >> 4; 259 + ids[3] = xy_data->touch34_id & 0xF; 260 + } 261 + 262 + static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data, 263 + int idx) 264 + { 265 + switch (idx) { 266 + case 0: 267 + return &xy_data->tch1; 268 + case 1: 269 + return &xy_data->tch2; 270 + case 2: 271 + return &xy_data->tch3; 272 + case 3: 273 + return &xy_data->tch4; 274 + default: 275 + return NULL; 276 + } 277 + } 278 + 279 + static void cyttsp_report_tchdata(struct cyttsp *ts) 280 + { 281 + struct cyttsp_xydata *xy_data = &ts->xy_data; 282 + struct input_dev *input = ts->input; 283 + int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat); 284 + const struct cyttsp_tch *tch; 285 + int ids[CY_MAX_ID]; 286 + int i; 287 + DECLARE_BITMAP(used, CY_MAX_ID); 288 + 289 + if (IS_LARGE_AREA(xy_data->tt_stat) == 1) { 290 + /* terminate all active tracks */ 291 + num_tch = 0; 292 + dev_dbg(ts->dev, "%s: Large area detected\n", __func__); 293 + } else if (num_tch > CY_MAX_FINGER) { 294 + /* terminate all active tracks */ 295 + num_tch = 0; 296 + dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__); 297 + } else if (IS_BAD_PKT(xy_data->tt_mode)) { 298 + /* terminate all active tracks */ 299 + num_tch = 0; 300 + dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__); 301 + } 302 + 303 + cyttsp_extract_track_ids(xy_data, ids); 304 + 305 + bitmap_zero(used, CY_MAX_ID); 306 + 307 + for (i = 0; i < num_tch; i++) { 308 + tch = cyttsp_get_tch(xy_data, i); 309 + 310 + input_mt_slot(input, ids[i]); 311 + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 312 + input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x)); 313 + input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y)); 314 + input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z); 315 + 316 + __set_bit(ids[i], used); 317 + } 318 + 319 + for (i = 0; i < CY_MAX_ID; i++) { 320 + if (test_bit(i, used)) 321 + continue; 322 + 323 + input_mt_slot(input, i); 324 + input_mt_report_slot_state(input, MT_TOOL_FINGER, false); 325 + } 326 + 327 + input_sync(input); 328 + } 329 + 330 + static irqreturn_t cyttsp_irq(int irq, void *handle) 331 + { 332 + struct cyttsp *ts = handle; 333 + int error; 334 + 335 + if (unlikely(ts->state == CY_BL_STATE)) { 336 + complete(&ts->bl_ready); 337 + goto out; 338 + } 339 + 340 + /* Get touch data from CYTTSP device */ 341 + error = ttsp_read_block_data(ts, CY_REG_BASE, 342 + sizeof(struct cyttsp_xydata), &ts->xy_data); 343 + if (error) 344 + goto out; 345 + 346 + /* provide flow control handshake */ 347 + if (ts->pdata->use_hndshk) { 348 + error = ttsp_send_command(ts, 349 + ts->xy_data.hst_mode ^ CY_HNDSHK_BIT); 350 + if (error) 351 + goto out; 352 + } 353 + 354 + if (unlikely(ts->state == CY_IDLE_STATE)) 355 + goto out; 356 + 357 + if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) { 358 + /* 359 + * TTSP device has reset back to bootloader mode. 360 + * Restore to operational mode. 361 + */ 362 + error = cyttsp_exit_bl_mode(ts); 363 + if (error) { 364 + dev_err(ts->dev, 365 + "Could not return to operational mode, err: %d\n", 366 + error); 367 + ts->state = CY_IDLE_STATE; 368 + } 369 + } else { 370 + cyttsp_report_tchdata(ts); 371 + } 372 + 373 + out: 374 + return IRQ_HANDLED; 375 + } 376 + 377 + static int cyttsp_power_on(struct cyttsp *ts) 378 + { 379 + int error; 380 + 381 + error = cyttsp_soft_reset(ts); 382 + if (error) 383 + return error; 384 + 385 + error = cyttsp_load_bl_regs(ts); 386 + if (error) 387 + return error; 388 + 389 + if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) && 390 + IS_VALID_APP(ts->bl_data.bl_status)) { 391 + error = cyttsp_exit_bl_mode(ts); 392 + if (error) 393 + return error; 394 + } 395 + 396 + if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE || 397 + IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) { 398 + return -ENODEV; 399 + } 400 + 401 + error = cyttsp_set_sysinfo_mode(ts); 402 + if (error) 403 + return error; 404 + 405 + error = cyttsp_set_sysinfo_regs(ts); 406 + if (error) 407 + return error; 408 + 409 + error = cyttsp_set_operational_mode(ts); 410 + if (error) 411 + return error; 412 + 413 + /* init active distance */ 414 + error = cyttsp_act_dist_setup(ts); 415 + if (error) 416 + return error; 417 + 418 + ts->state = CY_ACTIVE_STATE; 419 + 420 + return 0; 421 + } 422 + 423 + static int cyttsp_enable(struct cyttsp *ts) 424 + { 425 + int error; 426 + 427 + /* 428 + * The device firmware can wake on an I2C or SPI memory slave 429 + * address match. So just reading a register is sufficient to 430 + * wake up the device. The first read attempt will fail but it 431 + * will wake it up making the second read attempt successful. 432 + */ 433 + error = ttsp_read_block_data(ts, CY_REG_BASE, 434 + sizeof(ts->xy_data), &ts->xy_data); 435 + if (error) 436 + return error; 437 + 438 + if (GET_HSTMODE(ts->xy_data.hst_mode)) 439 + return -EIO; 440 + 441 + enable_irq(ts->irq); 442 + 443 + return 0; 444 + } 445 + 446 + static int cyttsp_disable(struct cyttsp *ts) 447 + { 448 + int error; 449 + 450 + error = ttsp_send_command(ts, CY_LOW_POWER_MODE); 451 + if (error) 452 + return error; 453 + 454 + disable_irq(ts->irq); 455 + 456 + return 0; 457 + } 458 + 459 + #ifdef CONFIG_PM_SLEEP 460 + static int cyttsp_suspend(struct device *dev) 461 + { 462 + struct cyttsp *ts = dev_get_drvdata(dev); 463 + int retval = 0; 464 + 465 + mutex_lock(&ts->input->mutex); 466 + 467 + if (ts->input->users) { 468 + retval = cyttsp_disable(ts); 469 + if (retval == 0) 470 + ts->suspended = true; 471 + } 472 + 473 + mutex_unlock(&ts->input->mutex); 474 + 475 + return retval; 476 + } 477 + 478 + static int cyttsp_resume(struct device *dev) 479 + { 480 + struct cyttsp *ts = dev_get_drvdata(dev); 481 + 482 + mutex_lock(&ts->input->mutex); 483 + 484 + if (ts->input->users) 485 + cyttsp_enable(ts); 486 + 487 + ts->suspended = false; 488 + 489 + mutex_unlock(&ts->input->mutex); 490 + 491 + return 0; 492 + } 493 + 494 + #endif 495 + 496 + SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume); 497 + EXPORT_SYMBOL_GPL(cyttsp_pm_ops); 498 + 499 + static int cyttsp_open(struct input_dev *dev) 500 + { 501 + struct cyttsp *ts = input_get_drvdata(dev); 502 + int retval = 0; 503 + 504 + if (!ts->suspended) 505 + retval = cyttsp_enable(ts); 506 + 507 + return retval; 508 + } 509 + 510 + static void cyttsp_close(struct input_dev *dev) 511 + { 512 + struct cyttsp *ts = input_get_drvdata(dev); 513 + 514 + if (!ts->suspended) 515 + cyttsp_disable(ts); 516 + } 517 + 518 + struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, 519 + struct device *dev, int irq, size_t xfer_buf_size) 520 + { 521 + const struct cyttsp_platform_data *pdata = dev->platform_data; 522 + struct cyttsp *ts; 523 + struct input_dev *input_dev; 524 + int error; 525 + 526 + if (!dev || !bus_ops || !pdata || !pdata->name || irq <= 0) { 527 + error = -EINVAL; 528 + goto err_out; 529 + } 530 + 531 + ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL); 532 + input_dev = input_allocate_device(); 533 + if (!ts || !input_dev) { 534 + error = -ENOMEM; 535 + goto err_free_mem; 536 + } 537 + 538 + ts->dev = dev; 539 + ts->input = input_dev; 540 + ts->pdata = dev->platform_data; 541 + ts->bus_ops = bus_ops; 542 + ts->irq = irq; 543 + 544 + init_completion(&ts->bl_ready); 545 + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); 546 + 547 + if (pdata->init) { 548 + error = pdata->init(); 549 + if (error) { 550 + dev_err(ts->dev, "platform init failed, err: %d\n", 551 + error); 552 + goto err_free_mem; 553 + } 554 + } 555 + 556 + input_dev->name = pdata->name; 557 + input_dev->phys = ts->phys; 558 + input_dev->id.bustype = bus_ops->bustype; 559 + input_dev->dev.parent = ts->dev; 560 + 561 + input_dev->open = cyttsp_open; 562 + input_dev->close = cyttsp_close; 563 + 564 + input_set_drvdata(input_dev, ts); 565 + 566 + __set_bit(EV_ABS, input_dev->evbit); 567 + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 568 + 0, pdata->maxx, 0, 0); 569 + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 570 + 0, pdata->maxy, 0, 0); 571 + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 572 + 0, CY_MAXZ, 0, 0); 573 + 574 + input_mt_init_slots(input_dev, CY_MAX_ID); 575 + 576 + error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, 577 + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 578 + pdata->name, ts); 579 + if (error) { 580 + dev_err(ts->dev, "failed to request IRQ %d, err: %d\n", 581 + ts->irq, error); 582 + goto err_platform_exit; 583 + } 584 + 585 + disable_irq(ts->irq); 586 + 587 + error = cyttsp_power_on(ts); 588 + if (error) 589 + goto err_free_irq; 590 + 591 + error = input_register_device(input_dev); 592 + if (error) { 593 + dev_err(ts->dev, "failed to register input device: %d\n", 594 + error); 595 + goto err_free_irq; 596 + } 597 + 598 + return ts; 599 + 600 + err_free_irq: 601 + free_irq(ts->irq, ts); 602 + err_platform_exit: 603 + if (pdata->exit) 604 + pdata->exit(); 605 + err_free_mem: 606 + input_free_device(input_dev); 607 + kfree(ts); 608 + err_out: 609 + return ERR_PTR(error); 610 + } 611 + EXPORT_SYMBOL_GPL(cyttsp_probe); 612 + 613 + void cyttsp_remove(struct cyttsp *ts) 614 + { 615 + free_irq(ts->irq, ts); 616 + input_unregister_device(ts->input); 617 + if (ts->pdata->exit) 618 + ts->pdata->exit(); 619 + kfree(ts); 620 + } 621 + EXPORT_SYMBOL_GPL(cyttsp_remove); 622 + 623 + MODULE_LICENSE("GPL"); 624 + MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core"); 625 + MODULE_AUTHOR("Cypress");
+149
drivers/input/touchscreen/cyttsp_core.h
··· 1 + /* 2 + * Header file for: 3 + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers. 4 + * For use with Cypress Txx3xx parts. 5 + * Supported parts include: 6 + * CY8CTST341 7 + * CY8CTMA340 8 + * 9 + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. 10 + * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * version 2, and only version 2, as published by the 15 + * Free Software Foundation. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License along 23 + * with this program; if not, write to the Free Software Foundation, Inc., 24 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 25 + * 26 + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> 27 + * 28 + */ 29 + 30 + 31 + #ifndef __CYTTSP_CORE_H__ 32 + #define __CYTTSP_CORE_H__ 33 + 34 + #include <linux/kernel.h> 35 + #include <linux/err.h> 36 + #include <linux/module.h> 37 + #include <linux/types.h> 38 + #include <linux/device.h> 39 + #include <linux/input/cyttsp.h> 40 + 41 + #define CY_NUM_RETRY 16 /* max number of retries for read ops */ 42 + 43 + struct cyttsp_tch { 44 + __be16 x, y; 45 + u8 z; 46 + } __packed; 47 + 48 + /* TrueTouch Standard Product Gen3 interface definition */ 49 + struct cyttsp_xydata { 50 + u8 hst_mode; 51 + u8 tt_mode; 52 + u8 tt_stat; 53 + struct cyttsp_tch tch1; 54 + u8 touch12_id; 55 + struct cyttsp_tch tch2; 56 + u8 gest_cnt; 57 + u8 gest_id; 58 + struct cyttsp_tch tch3; 59 + u8 touch34_id; 60 + struct cyttsp_tch tch4; 61 + u8 tt_undef[3]; 62 + u8 act_dist; 63 + u8 tt_reserved; 64 + } __packed; 65 + 66 + 67 + /* TTSP System Information interface definition */ 68 + struct cyttsp_sysinfo_data { 69 + u8 hst_mode; 70 + u8 mfg_cmd; 71 + u8 mfg_stat; 72 + u8 cid[3]; 73 + u8 tt_undef1; 74 + u8 uid[8]; 75 + u8 bl_verh; 76 + u8 bl_verl; 77 + u8 tts_verh; 78 + u8 tts_verl; 79 + u8 app_idh; 80 + u8 app_idl; 81 + u8 app_verh; 82 + u8 app_verl; 83 + u8 tt_undef[5]; 84 + u8 scn_typ; 85 + u8 act_intrvl; 86 + u8 tch_tmout; 87 + u8 lp_intrvl; 88 + }; 89 + 90 + /* TTSP Bootloader Register Map interface definition */ 91 + #define CY_BL_CHKSUM_OK 0x01 92 + struct cyttsp_bootloader_data { 93 + u8 bl_file; 94 + u8 bl_status; 95 + u8 bl_error; 96 + u8 blver_hi; 97 + u8 blver_lo; 98 + u8 bld_blver_hi; 99 + u8 bld_blver_lo; 100 + u8 ttspver_hi; 101 + u8 ttspver_lo; 102 + u8 appid_hi; 103 + u8 appid_lo; 104 + u8 appver_hi; 105 + u8 appver_lo; 106 + u8 cid_0; 107 + u8 cid_1; 108 + u8 cid_2; 109 + }; 110 + 111 + struct cyttsp; 112 + 113 + struct cyttsp_bus_ops { 114 + u16 bustype; 115 + int (*write)(struct cyttsp *ts, 116 + u8 addr, u8 length, const void *values); 117 + int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values); 118 + }; 119 + 120 + enum cyttsp_state { 121 + CY_IDLE_STATE, 122 + CY_ACTIVE_STATE, 123 + CY_BL_STATE, 124 + }; 125 + 126 + struct cyttsp { 127 + struct device *dev; 128 + int irq; 129 + struct input_dev *input; 130 + char phys[32]; 131 + const struct cyttsp_platform_data *pdata; 132 + const struct cyttsp_bus_ops *bus_ops; 133 + struct cyttsp_bootloader_data bl_data; 134 + struct cyttsp_sysinfo_data sysinfo_data; 135 + struct cyttsp_xydata xy_data; 136 + struct completion bl_ready; 137 + enum cyttsp_state state; 138 + bool suspended; 139 + 140 + u8 xfer_buf[] ____cacheline_aligned; 141 + }; 142 + 143 + struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, 144 + struct device *dev, int irq, size_t xfer_buf_size); 145 + void cyttsp_remove(struct cyttsp *ts); 146 + 147 + extern const struct dev_pm_ops cyttsp_pm_ops; 148 + 149 + #endif /* __CYTTSP_CORE_H__ */
+146
drivers/input/touchscreen/cyttsp_i2c.c
··· 1 + /* 2 + * Source for: 3 + * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver. 4 + * For use with Cypress Txx3xx parts. 5 + * Supported parts include: 6 + * CY8CTST341 7 + * CY8CTMA340 8 + * 9 + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. 10 + * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * version 2, and only version 2, as published by the 15 + * Free Software Foundation. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License along 23 + * with this program; if not, write to the Free Software Foundation, Inc., 24 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 25 + * 26 + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> 27 + * 28 + */ 29 + 30 + #include "cyttsp_core.h" 31 + 32 + #include <linux/i2c.h> 33 + #include <linux/input.h> 34 + 35 + #define CY_I2C_DATA_SIZE 128 36 + 37 + static int cyttsp_i2c_read_block_data(struct cyttsp *ts, 38 + u8 addr, u8 length, void *values) 39 + { 40 + struct i2c_client *client = to_i2c_client(ts->dev); 41 + struct i2c_msg msgs[] = { 42 + { 43 + .addr = client->addr, 44 + .flags = 0, 45 + .len = 1, 46 + .buf = &addr, 47 + }, 48 + { 49 + .addr = client->addr, 50 + .flags = I2C_M_RD, 51 + .len = length, 52 + .buf = values, 53 + }, 54 + }; 55 + int retval; 56 + 57 + retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 58 + if (retval < 0) 59 + return retval; 60 + 61 + return retval != ARRAY_SIZE(msgs) ? -EIO : 0; 62 + } 63 + 64 + static int cyttsp_i2c_write_block_data(struct cyttsp *ts, 65 + u8 addr, u8 length, const void *values) 66 + { 67 + struct i2c_client *client = to_i2c_client(ts->dev); 68 + int retval; 69 + 70 + ts->xfer_buf[0] = addr; 71 + memcpy(&ts->xfer_buf[1], values, length); 72 + 73 + retval = i2c_master_send(client, ts->xfer_buf, length + 1); 74 + 75 + return retval < 0 ? retval : 0; 76 + } 77 + 78 + static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = { 79 + .bustype = BUS_I2C, 80 + .write = cyttsp_i2c_write_block_data, 81 + .read = cyttsp_i2c_read_block_data, 82 + }; 83 + 84 + static int __devinit cyttsp_i2c_probe(struct i2c_client *client, 85 + const struct i2c_device_id *id) 86 + { 87 + struct cyttsp *ts; 88 + 89 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 90 + dev_err(&client->dev, "I2C functionality not Supported\n"); 91 + return -EIO; 92 + } 93 + 94 + ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq, 95 + CY_I2C_DATA_SIZE); 96 + 97 + if (IS_ERR(ts)) 98 + return PTR_ERR(ts); 99 + 100 + i2c_set_clientdata(client, ts); 101 + 102 + return 0; 103 + } 104 + 105 + static int __devexit cyttsp_i2c_remove(struct i2c_client *client) 106 + { 107 + struct cyttsp *ts = i2c_get_clientdata(client); 108 + 109 + cyttsp_remove(ts); 110 + 111 + return 0; 112 + } 113 + 114 + static const struct i2c_device_id cyttsp_i2c_id[] = { 115 + { CY_I2C_NAME, 0 }, 116 + { } 117 + }; 118 + MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); 119 + 120 + static struct i2c_driver cyttsp_i2c_driver = { 121 + .driver = { 122 + .name = CY_I2C_NAME, 123 + .owner = THIS_MODULE, 124 + .pm = &cyttsp_pm_ops, 125 + }, 126 + .probe = cyttsp_i2c_probe, 127 + .remove = __devexit_p(cyttsp_i2c_remove), 128 + .id_table = cyttsp_i2c_id, 129 + }; 130 + 131 + static int __init cyttsp_i2c_init(void) 132 + { 133 + return i2c_add_driver(&cyttsp_i2c_driver); 134 + } 135 + module_init(cyttsp_i2c_init); 136 + 137 + static void __exit cyttsp_i2c_exit(void) 138 + { 139 + return i2c_del_driver(&cyttsp_i2c_driver); 140 + } 141 + module_exit(cyttsp_i2c_exit); 142 + 143 + MODULE_LICENSE("GPL"); 144 + MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"); 145 + MODULE_AUTHOR("Cypress"); 146 + MODULE_ALIAS("i2c:cyttsp");
+210
drivers/input/touchscreen/cyttsp_spi.c
··· 1 + /* 2 + * Source for: 3 + * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver. 4 + * For use with Cypress Txx3xx parts. 5 + * Supported parts include: 6 + * CY8CTST341 7 + * CY8CTMA340 8 + * 9 + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. 10 + * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * version 2, and only version 2, as published by the 15 + * Free Software Foundation. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License along 23 + * with this program; if not, write to the Free Software Foundation, Inc., 24 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 25 + * 26 + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com> 27 + * 28 + */ 29 + 30 + #include "cyttsp_core.h" 31 + 32 + #include <linux/delay.h> 33 + #include <linux/input.h> 34 + #include <linux/spi/spi.h> 35 + 36 + #define CY_SPI_WR_OP 0x00 /* r/~w */ 37 + #define CY_SPI_RD_OP 0x01 38 + #define CY_SPI_CMD_BYTES 4 39 + #define CY_SPI_SYNC_BYTE 2 40 + #define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */ 41 + #define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */ 42 + #define CY_SPI_DATA_SIZE 128 43 + #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) 44 + #define CY_SPI_BITS_PER_WORD 8 45 + 46 + static int cyttsp_spi_xfer(struct cyttsp *ts, 47 + u8 op, u8 reg, u8 *buf, int length) 48 + { 49 + struct spi_device *spi = to_spi_device(ts->dev); 50 + struct spi_message msg; 51 + struct spi_transfer xfer[2]; 52 + u8 *wr_buf = &ts->xfer_buf[0]; 53 + u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE]; 54 + int retval; 55 + int i; 56 + 57 + if (length > CY_SPI_DATA_SIZE) { 58 + dev_err(ts->dev, "%s: length %d is too big.\n", 59 + __func__, length); 60 + return -EINVAL; 61 + } 62 + 63 + memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE); 64 + memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE); 65 + 66 + wr_buf[0] = 0x00; /* header byte 0 */ 67 + wr_buf[1] = 0xFF; /* header byte 1 */ 68 + wr_buf[2] = reg; /* reg index */ 69 + wr_buf[3] = op; /* r/~w */ 70 + if (op == CY_SPI_WR_OP) 71 + memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); 72 + 73 + memset(xfer, 0, sizeof(xfer)); 74 + spi_message_init(&msg); 75 + 76 + /* 77 + We set both TX and RX buffers because Cypress TTSP 78 + requires full duplex operation. 79 + */ 80 + xfer[0].tx_buf = wr_buf; 81 + xfer[0].rx_buf = rd_buf; 82 + switch (op) { 83 + case CY_SPI_WR_OP: 84 + xfer[0].len = length + CY_SPI_CMD_BYTES; 85 + spi_message_add_tail(&xfer[0], &msg); 86 + break; 87 + 88 + case CY_SPI_RD_OP: 89 + xfer[0].len = CY_SPI_CMD_BYTES; 90 + spi_message_add_tail(&xfer[0], &msg); 91 + 92 + xfer[1].rx_buf = buf; 93 + xfer[1].len = length; 94 + spi_message_add_tail(&xfer[1], &msg); 95 + break; 96 + 97 + default: 98 + dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op); 99 + return -EINVAL; 100 + } 101 + 102 + retval = spi_sync(spi, &msg); 103 + if (retval < 0) { 104 + dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n", 105 + __func__, retval, xfer[1].len, op); 106 + 107 + /* 108 + * do not return here since was a bad ACK sequence 109 + * let the following ACK check handle any errors and 110 + * allow silent retries 111 + */ 112 + } 113 + 114 + if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 || 115 + rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) { 116 + 117 + dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op); 118 + 119 + for (i = 0; i < CY_SPI_CMD_BYTES; i++) 120 + dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n", 121 + __func__, i, rd_buf[i]); 122 + for (i = 0; i < length; i++) 123 + dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n", 124 + __func__, i, buf[i]); 125 + 126 + return -EIO; 127 + } 128 + 129 + return 0; 130 + } 131 + 132 + static int cyttsp_spi_read_block_data(struct cyttsp *ts, 133 + u8 addr, u8 length, void *data) 134 + { 135 + return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length); 136 + } 137 + 138 + static int cyttsp_spi_write_block_data(struct cyttsp *ts, 139 + u8 addr, u8 length, const void *data) 140 + { 141 + return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length); 142 + } 143 + 144 + static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = { 145 + .bustype = BUS_SPI, 146 + .write = cyttsp_spi_write_block_data, 147 + .read = cyttsp_spi_read_block_data, 148 + }; 149 + 150 + static int __devinit cyttsp_spi_probe(struct spi_device *spi) 151 + { 152 + struct cyttsp *ts; 153 + int error; 154 + 155 + /* Set up SPI*/ 156 + spi->bits_per_word = CY_SPI_BITS_PER_WORD; 157 + spi->mode = SPI_MODE_0; 158 + error = spi_setup(spi); 159 + if (error < 0) { 160 + dev_err(&spi->dev, "%s: SPI setup error %d\n", 161 + __func__, error); 162 + return error; 163 + } 164 + 165 + ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq, 166 + CY_SPI_DATA_BUF_SIZE * 2); 167 + if (IS_ERR(ts)) 168 + return PTR_ERR(ts); 169 + 170 + spi_set_drvdata(spi, ts); 171 + 172 + return 0; 173 + } 174 + 175 + static int __devexit cyttsp_spi_remove(struct spi_device *spi) 176 + { 177 + struct cyttsp *ts = spi_get_drvdata(spi); 178 + 179 + cyttsp_remove(ts); 180 + 181 + return 0; 182 + } 183 + 184 + static struct spi_driver cyttsp_spi_driver = { 185 + .driver = { 186 + .name = CY_SPI_NAME, 187 + .owner = THIS_MODULE, 188 + .pm = &cyttsp_pm_ops, 189 + }, 190 + .probe = cyttsp_spi_probe, 191 + .remove = __devexit_p(cyttsp_spi_remove), 192 + }; 193 + 194 + static int __init cyttsp_spi_init(void) 195 + { 196 + return spi_register_driver(&cyttsp_spi_driver); 197 + } 198 + module_init(cyttsp_spi_init); 199 + 200 + static void __exit cyttsp_spi_exit(void) 201 + { 202 + spi_unregister_driver(&cyttsp_spi_driver); 203 + } 204 + module_exit(cyttsp_spi_exit); 205 + 206 + MODULE_ALIAS("spi:cyttsp"); 207 + MODULE_LICENSE("GPL"); 208 + MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver"); 209 + MODULE_AUTHOR("Cypress"); 210 + MODULE_ALIAS("spi:cyttsp");
+58
include/linux/input/cyttsp.h
··· 1 + /* 2 + * Header file for: 3 + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers. 4 + * For use with Cypress Txx3xx parts. 5 + * Supported parts include: 6 + * CY8CTST341 7 + * CY8CTMA340 8 + * 9 + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. 10 + * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> 11 + * 12 + * This program is free software; you can redistribute it and/or 13 + * modify it under the terms of the GNU General Public License 14 + * version 2, and only version 2, as published by the 15 + * Free Software Foundation. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License along 23 + * with this program; if not, write to the Free Software Foundation, Inc., 24 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 25 + * 26 + * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com) 27 + * 28 + */ 29 + #ifndef _CYTTSP_H_ 30 + #define _CYTTSP_H_ 31 + 32 + #define CY_SPI_NAME "cyttsp-spi" 33 + #define CY_I2C_NAME "cyttsp-i2c" 34 + /* Active Power state scanning/processing refresh interval */ 35 + #define CY_ACT_INTRVL_DFLT 0x00 /* ms */ 36 + /* touch timeout for the Active power */ 37 + #define CY_TCH_TMOUT_DFLT 0xFF /* ms */ 38 + /* Low Power state scanning/processing refresh interval */ 39 + #define CY_LP_INTRVL_DFLT 0x0A /* ms */ 40 + /* Active distance in pixels for a gesture to be reported */ 41 + #define CY_ACT_DIST_DFLT 0xF8 /* pixels */ 42 + 43 + struct cyttsp_platform_data { 44 + u32 maxx; 45 + u32 maxy; 46 + bool use_hndshk; 47 + u8 act_dist; /* Active distance */ 48 + u8 act_intrvl; /* Active refresh interval; ms */ 49 + u8 tch_tmout; /* Active touch timeout; ms */ 50 + u8 lp_intrvl; /* Low power refresh interval; ms */ 51 + int (*init)(void); 52 + void (*exit)(void); 53 + char *name; 54 + s16 irq_gpio; 55 + u8 *bl_keys; 56 + }; 57 + 58 + #endif /* _CYTTSP_H_ */