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

Input: cyttsp4 - SPI driver for Cypress TMA4XX touchscreen devices

Cypress TrueTouch(tm) Standard Product controllers,
Generation4 devices, SPI adapter module.

This driver adds communication support with TTSP controller
using SPI bus.

Signed-off-by: Ferruh Yigit <fery@cypress.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Javier Martinez Canillas <javier@dowhile0.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Ferruh Yigit and committed by
Dmitry Torokhov
67bf12ca 4f9e8680

+215
+9
drivers/input/touchscreen/Kconfig
··· 188 188 To compile this driver as a module, choose M here: the 189 189 module will be called cyttsp4_i2c. 190 190 191 + config TOUCHSCREEN_CYTTSP4_SPI 192 + tristate "support SPI bus connection" 193 + depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER 194 + help 195 + Say Y here if the touchscreen is connected via SPI bus. 196 + 197 + To compile this driver as a module, choose M here: the 198 + module will be called cyttsp4_spi. 199 + 191 200 config TOUCHSCREEN_DA9034 192 201 tristate "Touchscreen support for Dialog Semiconductor DA9034" 193 202 depends on PMIC_DA903X
+1
drivers/input/touchscreen/Makefile
··· 22 22 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o 23 23 obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o 24 24 obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o 25 + obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o 25 26 obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o 26 27 obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o 27 28 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
+205
drivers/input/touchscreen/cyttsp4_spi.c
··· 1 + /* 2 + * Source for: 3 + * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver. 4 + * For use with Cypress Txx4xx parts. 5 + * Supported parts include: 6 + * TMA4XX 7 + * TMA1036 8 + * 9 + * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc. 10 + * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org> 11 + * Copyright (C) 2013 Cypress Semiconductor 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * version 2, and only version 2, as published by the 16 + * Free Software Foundation. 17 + * 18 + * This program is distributed in the hope that it will be useful, 19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 + * GNU General Public License for more details. 22 + * 23 + * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com> 24 + * 25 + */ 26 + 27 + #include "cyttsp4_core.h" 28 + 29 + #include <linux/delay.h> 30 + #include <linux/input.h> 31 + #include <linux/spi/spi.h> 32 + 33 + #define CY_SPI_WR_OP 0x00 /* r/~w */ 34 + #define CY_SPI_RD_OP 0x01 35 + #define CY_SPI_BITS_PER_WORD 8 36 + #define CY_SPI_A8_BIT 0x02 37 + #define CY_SPI_WR_HEADER_BYTES 2 38 + #define CY_SPI_RD_HEADER_BYTES 1 39 + #define CY_SPI_CMD_BYTES 2 40 + #define CY_SPI_SYNC_BYTE 0 41 + #define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */ 42 + #define CY_SPI_DATA_SIZE (2 * 256) 43 + 44 + #define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE) 45 + 46 + static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf, 47 + u8 op, u8 reg, u8 *buf, int length) 48 + { 49 + struct spi_device *spi = to_spi_device(dev); 50 + struct spi_message msg; 51 + struct spi_transfer xfer[2]; 52 + u8 *wr_buf = &xfer_buf[0]; 53 + u8 rd_buf[CY_SPI_CMD_BYTES]; 54 + int retval; 55 + int i; 56 + 57 + if (length > CY_SPI_DATA_SIZE) { 58 + dev_err(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_CMD_BYTES); 65 + 66 + if (reg > 255) 67 + wr_buf[0] = op + CY_SPI_A8_BIT; 68 + else 69 + wr_buf[0] = op; 70 + if (op == CY_SPI_WR_OP) 71 + wr_buf[1] = reg % 256; 72 + if (op == CY_SPI_WR_OP && length > 0) 73 + memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length); 74 + 75 + memset(xfer, 0, sizeof(xfer)); 76 + spi_message_init(&msg); 77 + 78 + /* 79 + We set both TX and RX buffers because Cypress TTSP 80 + requires full duplex operation. 81 + */ 82 + xfer[0].tx_buf = wr_buf; 83 + xfer[0].rx_buf = rd_buf; 84 + switch (op) { 85 + case CY_SPI_WR_OP: 86 + xfer[0].len = length + CY_SPI_CMD_BYTES; 87 + spi_message_add_tail(&xfer[0], &msg); 88 + break; 89 + 90 + case CY_SPI_RD_OP: 91 + xfer[0].len = CY_SPI_RD_HEADER_BYTES; 92 + spi_message_add_tail(&xfer[0], &msg); 93 + 94 + xfer[1].rx_buf = buf; 95 + xfer[1].len = length; 96 + spi_message_add_tail(&xfer[1], &msg); 97 + break; 98 + 99 + default: 100 + dev_err(dev, "%s: bad operation code=%d\n", __func__, op); 101 + return -EINVAL; 102 + } 103 + 104 + retval = spi_sync(spi, &msg); 105 + if (retval < 0) { 106 + dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n", 107 + __func__, retval, xfer[1].len, op); 108 + 109 + /* 110 + * do not return here since was a bad ACK sequence 111 + * let the following ACK check handle any errors and 112 + * allow silent retries 113 + */ 114 + } 115 + 116 + if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) { 117 + dev_dbg(dev, "%s: operation %d failed\n", __func__, op); 118 + 119 + for (i = 0; i < CY_SPI_CMD_BYTES; i++) 120 + dev_dbg(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(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 device *dev, u8 *xfer_buf, 133 + u8 addr, u8 length, void *data) 134 + { 135 + int rc; 136 + 137 + rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0); 138 + if (rc) 139 + return rc; 140 + else 141 + return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data, 142 + length); 143 + } 144 + 145 + static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf, 146 + u8 addr, u8 length, const void *data) 147 + { 148 + return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data, 149 + length); 150 + } 151 + 152 + static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = { 153 + .bustype = BUS_SPI, 154 + .write = cyttsp_spi_write_block_data, 155 + .read = cyttsp_spi_read_block_data, 156 + }; 157 + 158 + static int cyttsp4_spi_probe(struct spi_device *spi) 159 + { 160 + struct cyttsp4 *ts; 161 + int error; 162 + 163 + /* Set up SPI*/ 164 + spi->bits_per_word = CY_SPI_BITS_PER_WORD; 165 + spi->mode = SPI_MODE_0; 166 + error = spi_setup(spi); 167 + if (error < 0) { 168 + dev_err(&spi->dev, "%s: SPI setup error %d\n", 169 + __func__, error); 170 + return error; 171 + } 172 + 173 + ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq, 174 + CY_SPI_DATA_BUF_SIZE); 175 + 176 + if (IS_ERR(ts)) 177 + return PTR_ERR(ts); 178 + 179 + return 0; 180 + } 181 + 182 + static int cyttsp4_spi_remove(struct spi_device *spi) 183 + { 184 + struct cyttsp4 *ts = spi_get_drvdata(spi); 185 + cyttsp4_remove(ts); 186 + 187 + return 0; 188 + } 189 + 190 + static struct spi_driver cyttsp4_spi_driver = { 191 + .driver = { 192 + .name = CYTTSP4_SPI_NAME, 193 + .owner = THIS_MODULE, 194 + .pm = &cyttsp4_pm_ops, 195 + }, 196 + .probe = cyttsp4_spi_probe, 197 + .remove = cyttsp4_spi_remove, 198 + }; 199 + 200 + module_spi_driver(cyttsp4_spi_driver); 201 + 202 + MODULE_LICENSE("GPL"); 203 + MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver"); 204 + MODULE_AUTHOR("Cypress"); 205 + MODULE_ALIAS("spi:cyttsp4");