From patchwork Sat Sep 3 05:50:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Javier Martinez Canillas X-Patchwork-Id: 1123222 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p835ppiF019463 for ; Sat, 3 Sep 2011 05:51:52 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754447Ab1ICFvI (ORCPT ); Sat, 3 Sep 2011 01:51:08 -0400 Received: from mail-ww0-f44.google.com ([74.125.82.44]:45169 "EHLO mail-ww0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754201Ab1ICFvF (ORCPT ); Sat, 3 Sep 2011 01:51:05 -0400 Received: by mail-ww0-f44.google.com with SMTP id 5so3572204wwf.1 for ; Fri, 02 Sep 2011 22:51:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=vxnwRMJIAFk8P0jvFqYWzeC8CLjsx52VV3/QURFLTgU=; b=H21YJKt8R0gzEcj/8CIXLmSVli07GRHHqAxX1PkNy/YdM1qzCQ/zbBA/rS7sHI76EG aWdL0Dsjrk+Sk+qavtg6PCM6oifiqX0V37iORJQyF4QvCmx9XKekkECvtKIkISxgZbNm 9WTlyT1tLimNVGXfL7uZhEANE9rOwAOcFQXjU= Received: by 10.216.154.6 with SMTP id g6mr1809941wek.81.1315029063429; Fri, 02 Sep 2011 22:51:03 -0700 (PDT) Received: from localhost.localdomain (215.Red-83-57-22.dynamicIP.rima-tde.net [83.57.22.215]) by mx.google.com with ESMTPS id y12sm1099877wbo.25.2011.09.02.22.51.01 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 02 Sep 2011 22:51:02 -0700 (PDT) From: Javier Martinez Canillas To: Kevin McNeely Cc: Dmitry Torokhov , Henrik Rydberg , Greg Kroah-Hartman , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Javier Martinez Canillas Subject: [PATCH V2 3/3] Input: cyttsp - add support for Cypress TTSP touchscreen SPI bus interface Date: Sat, 3 Sep 2011 07:50:42 +0200 Message-Id: <1315029042-27513-4-git-send-email-martinez.javier@gmail.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1315029042-27513-1-git-send-email-martinez.javier@gmail.com> References: <1315029042-27513-1-git-send-email-martinez.javier@gmail.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Sat, 03 Sep 2011 05:51:52 +0000 (UTC) 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 add supports for the Cypress TTSP SPI bus interface. The original author of the driver is Kevin McNeely Signed-off-by: Javier Martinez Canillas --- Changes since v1: Fix issues called out by Dmitry Torokhov - Extract the IRQ from the spi client data and pass to cyttsp_core_init - Remove the extra retries and limit the retries to the cyttsp_core.c read/write block functions. - Cleanup cyttsp_spi_xfer(), check ACK in write operation and fix special EIO case to show its meaning. drivers/input/touchscreen/cyttsp/Kconfig | 12 + drivers/input/touchscreen/cyttsp/Makefile | 1 + drivers/input/touchscreen/cyttsp/cyttsp_spi.c | 293 +++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 0 deletions(-) create mode 100644 drivers/input/touchscreen/cyttsp/cyttsp_spi.c diff --git a/drivers/input/touchscreen/cyttsp/Kconfig b/drivers/input/touchscreen/cyttsp/Kconfig index 256642d..e72c66c 100644 --- a/drivers/input/touchscreen/cyttsp/Kconfig +++ b/drivers/input/touchscreen/cyttsp/Kconfig @@ -14,3 +14,15 @@ config TOUCHSCREEN_CYTTSP_I2C To compile this driver as a module, choose M here: the module will be called cyttsp-i2c. + +config TOUCHSCREEN_CYTTSP_SPI + tristate "Cypress TTSP spi touchscreen" + depends on SPI_MASTER && TOUCHSCREEN_CYTTSP_CORE + help + Say Y here if you have a Cypress TTSP touchscreen + connected to your with an SPI interface. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called cyttsp-spi. diff --git a/drivers/input/touchscreen/cyttsp/Makefile b/drivers/input/touchscreen/cyttsp/Makefile index 9101dc9..687eeaa 100644 --- a/drivers/input/touchscreen/cyttsp/Makefile +++ b/drivers/input/touchscreen/cyttsp/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o +obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o diff --git a/drivers/input/touchscreen/cyttsp/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp/cyttsp_spi.c new file mode 100644 index 0000000..71a586a --- /dev/null +++ b/drivers/input/touchscreen/cyttsp/cyttsp_spi.c @@ -0,0 +1,293 @@ +/* + * Source for: + * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver. + * For use with Cypress Txx3xx parts. + * Supported parts include: + * CY8CTST341 + * CY8CTMA340 + * + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, and only version 2, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contact Cypress Semiconductor at www.cypress.com + * + */ + +#include "cyttsp_core.h" + +#include +#include + +#define CY_SPI_WR_OP 0x00 /* r/~w */ +#define CY_SPI_RD_OP 0x01 +#define CY_SPI_CMD_BYTES 4 +#define CY_SPI_SYNC_BYTE 2 +#define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */ +#define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */ +#define CY_SPI_DATA_SIZE 128 +#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) +#define CY_SPI_BITS_PER_WORD 8 + +struct cyttsp_spi { + struct cyttsp_bus_ops bus_ops; + struct spi_device *spi_client; + void *ttsp_client; + u8 wr_buf[CY_SPI_DATA_BUF_SIZE]; + u8 rd_buf[CY_SPI_DATA_BUF_SIZE]; +}; + +static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts, + u8 reg, u8 *buf, int length) +{ + struct spi_message msg; + struct spi_transfer xfer[2]; + u8 *wr_buf = ts->wr_buf; + u8 *rd_buf = ts->rd_buf; + int retval; + + if (length > CY_SPI_DATA_SIZE) { + dev_dbg(ts->bus_ops.dev, + "%s: length %d is too big.\n", + __func__, length); + return -EINVAL; + } + + memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE); + memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE); + + wr_buf[0] = 0x00; /* header byte 0 */ + wr_buf[1] = 0xFF; /* header byte 1 */ + wr_buf[2] = reg; /* reg index */ + wr_buf[3] = op; /* r/~w */ + if (op == CY_SPI_WR_OP) + memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); + + memset((void *)xfer, 0, sizeof(xfer)); + spi_message_init(&msg); + + /* + We set both TX and RX buffers because Cypress TTSP + requires full duplex operation. + */ + xfer[0].tx_buf = wr_buf; + xfer[0].rx_buf = rd_buf; + if (op == CY_SPI_WR_OP) { + xfer[0].len = length + CY_SPI_CMD_BYTES; + spi_message_add_tail(&xfer[0], &msg); + } else if (op == CY_SPI_RD_OP) { + xfer[0].len = CY_SPI_CMD_BYTES; + spi_message_add_tail(&xfer[0], &msg); + + xfer[1].rx_buf = buf; + xfer[1].len = length; + spi_message_add_tail(&xfer[1], &msg); + } + + retval = spi_sync(ts->spi_client, &msg); + if (retval < 0) { + dev_dbg(ts->bus_ops.dev, + "%s: spi_sync() error %d, len=%d, op=%d\n", + __func__, retval, xfer[1].len, op); + + /* + * do not return here since was a bad ACK sequence + * let the following ACK check handle any errors and + * allow silent retries + */ + } + + if ((rd_buf[CY_SPI_SYNC_BYTE] == CY_SPI_SYNC_ACK1) && + (rd_buf[CY_SPI_SYNC_BYTE+1] == CY_SPI_SYNC_ACK2)) + retval = 0; + else { + int i; + for (i = 0; i < (CY_SPI_CMD_BYTES); i++) + dev_dbg(ts->bus_ops.dev, + "%s: test rd_buf[%d]:0x%02x\n", + __func__, i, rd_buf[i]); + for (i = 0; i < (length); i++) + dev_dbg(ts->bus_ops.dev, + "%s: test buf[%d]:0x%02x\n", + __func__, i, buf[i]); + + /* signal ACK error so silent retry */ + retval = 1; + } + + return retval; +} + +static s32 ttsp_spi_read_block_data(void *handle, u8 addr, + u8 length, void *data) +{ + struct cyttsp_spi *ts = + container_of(handle, struct cyttsp_spi, bus_ops); + int retval; + + retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length); + if (retval < 0) + pr_err("%s: ttsp_spi_read_block_data failed\n", + __func__); + + /* + * Do not print the above error if the data sync bytes were not found. + * This is a normal condition for the bootloader loader startup and need + * to retry until data sync bytes are found. + */ + if (retval > 0) + retval = -EIO; /* now signal fail; so retry can be done */ + + return retval; +} + +static s32 ttsp_spi_write_block_data(void *handle, u8 addr, + u8 length, const void *data) +{ + struct cyttsp_spi *ts = + container_of(handle, struct cyttsp_spi, bus_ops); + int retval; + + retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data, length); + if (retval < 0) + pr_err("%s: ttsp_spi_write_block_data failed\n", + __func__); + + /* + * Do not print the above error if the data sync bytes were not found. + * This is a normal condition for the bootloader loader startup and need + * to retry until data sync bytes are found. + */ + if (retval > 0) + retval = -EIO; /* now signal fail; so retry can be done */ + + return retval; +} + +static s32 ttsp_spi_tch_ext(void *handle, void *values) +{ + struct cyttsp_spi *ts = + container_of(handle, struct cyttsp_spi, bus_ops); + int retval = 0; + + /* + * TODO: Add custom touch extension handling code here + * set: retval < 0 for any returned system errors, + * retval = 0 if normal touch handling is required, + * retval > 0 if normal touch handling is *not* required + */ + + if (!ts || !values) + retval = -EINVAL; + + return retval; +} + +static int __devinit cyttsp_spi_probe(struct spi_device *spi) +{ + struct cyttsp_spi *ts; + int retval; + + /* Set up SPI*/ + spi->bits_per_word = CY_SPI_BITS_PER_WORD; + spi->mode = SPI_MODE_0; + retval = spi_setup(spi); + if (retval < 0) { + dev_dbg(&spi->dev, "%s: SPI setup error %d\n", + __func__, retval); + return retval; + } + + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (!ts) { + dev_dbg(&spi->dev, "%s: Error, kzalloc\n", __func__); + return -ENOMEM; + } + + ts->spi_client = spi; + dev_set_drvdata(&spi->dev, ts); + ts->bus_ops.write = ttsp_spi_write_block_data; + ts->bus_ops.read = ttsp_spi_read_block_data; + ts->bus_ops.ext = ttsp_spi_tch_ext; + ts->bus_ops.dev = &spi->dev; + + ts->ttsp_client = cyttsp_core_init(&ts->bus_ops, &spi->dev, spi->irq); + if (IS_ERR(ts->ttsp_client)) { + int retval = PTR_ERR(ts->ttsp_client); + kfree(ts); + return retval; + } + + dev_dbg(ts->bus_ops.dev, "%s: Registration complete\n", __func__); + + return 0; +} + +static int __devexit cyttsp_spi_remove(struct spi_device *spi) +{ + struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev); + + cyttsp_core_release(ts->ttsp_client); + kfree(ts); + return 0; +} + +#ifdef CONFIG_PM +static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t message) +{ + struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev); + + return cyttsp_suspend(ts->ttsp_client); +} + +static int cyttsp_spi_resume(struct spi_device *spi) +{ + struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev); + + return cyttsp_resume(ts->ttsp_client); +} +#endif + +static struct spi_driver cyttsp_spi_driver = { + .driver = { + .name = CY_SPI_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = cyttsp_spi_probe, + .remove = __devexit_p(cyttsp_spi_remove), +#ifdef CONFIG_PM + .suspend = cyttsp_spi_suspend, + .resume = cyttsp_spi_resume, +#endif +}; + +static int __init cyttsp_spi_init(void) +{ + return spi_register_driver(&cyttsp_spi_driver); +} +module_init(cyttsp_spi_init); + +static void __exit cyttsp_spi_exit(void) +{ + spi_unregister_driver(&cyttsp_spi_driver); +} +module_exit(cyttsp_spi_exit); + +MODULE_ALIAS("spi:cyttsp"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver"); +MODULE_AUTHOR("Cypress"); +