linux/drivers/input/touchscreen/cyttsp4_spi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Source for:
   4 * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
   5 * For use with Cypress Txx4xx parts.
   6 * Supported parts include:
   7 * TMA4XX
   8 * TMA1036
   9 *
  10 * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
  11 * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
  12 * Copyright (C) 2013 Cypress Semiconductor
  13 *
  14 * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
  15 */
  16
  17#include "cyttsp4_core.h"
  18
  19#include <linux/delay.h>
  20#include <linux/input.h>
  21#include <linux/spi/spi.h>
  22
  23#define CY_SPI_WR_OP            0x00 /* r/~w */
  24#define CY_SPI_RD_OP            0x01
  25#define CY_SPI_BITS_PER_WORD    8
  26#define CY_SPI_A8_BIT           0x02
  27#define CY_SPI_WR_HEADER_BYTES  2
  28#define CY_SPI_RD_HEADER_BYTES  1
  29#define CY_SPI_CMD_BYTES        2
  30#define CY_SPI_SYNC_BYTE        0
  31#define CY_SPI_SYNC_ACK         0x62 /* from TRM *A protocol */
  32#define CY_SPI_DATA_SIZE        (2 * 256)
  33
  34#define CY_SPI_DATA_BUF_SIZE    (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
  35
  36static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
  37                           u8 op, u16 reg, u8 *buf, int length)
  38{
  39        struct spi_device *spi = to_spi_device(dev);
  40        struct spi_message msg;
  41        struct spi_transfer xfer[2];
  42        u8 *wr_buf = &xfer_buf[0];
  43        u8 rd_buf[CY_SPI_CMD_BYTES];
  44        int retval;
  45        int i;
  46
  47        if (length > CY_SPI_DATA_SIZE) {
  48                dev_err(dev, "%s: length %d is too big.\n",
  49                        __func__, length);
  50                return -EINVAL;
  51        }
  52
  53        memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
  54        memset(rd_buf, 0, CY_SPI_CMD_BYTES);
  55
  56        wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0);
  57        if (op == CY_SPI_WR_OP) {
  58                wr_buf[1] = reg & 0xFF;
  59                if (length > 0)
  60                        memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
  61        }
  62
  63        memset(xfer, 0, sizeof(xfer));
  64        spi_message_init(&msg);
  65
  66        /*
  67          We set both TX and RX buffers because Cypress TTSP
  68          requires full duplex operation.
  69        */
  70        xfer[0].tx_buf = wr_buf;
  71        xfer[0].rx_buf = rd_buf;
  72        switch (op) {
  73        case CY_SPI_WR_OP:
  74                xfer[0].len = length + CY_SPI_CMD_BYTES;
  75                spi_message_add_tail(&xfer[0], &msg);
  76                break;
  77
  78        case CY_SPI_RD_OP:
  79                xfer[0].len = CY_SPI_RD_HEADER_BYTES;
  80                spi_message_add_tail(&xfer[0], &msg);
  81
  82                xfer[1].rx_buf = buf;
  83                xfer[1].len = length;
  84                spi_message_add_tail(&xfer[1], &msg);
  85                break;
  86
  87        default:
  88                dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
  89                return -EINVAL;
  90        }
  91
  92        retval = spi_sync(spi, &msg);
  93        if (retval < 0) {
  94                dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
  95                        __func__, retval, xfer[1].len, op);
  96
  97                /*
  98                 * do not return here since was a bad ACK sequence
  99                 * let the following ACK check handle any errors and
 100                 * allow silent retries
 101                 */
 102        }
 103
 104        if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
 105                dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
 106
 107                for (i = 0; i < CY_SPI_CMD_BYTES; i++)
 108                        dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
 109                                __func__, i, rd_buf[i]);
 110                for (i = 0; i < length; i++)
 111                        dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
 112                                __func__, i, buf[i]);
 113
 114                return -EIO;
 115        }
 116
 117        return 0;
 118}
 119
 120static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
 121                                      u16 addr, u8 length, void *data)
 122{
 123        int rc;
 124
 125        rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
 126        if (rc)
 127                return rc;
 128        else
 129                return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
 130                                length);
 131}
 132
 133static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
 134                                       u16 addr, u8 length, const void *data)
 135{
 136        return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
 137                        length);
 138}
 139
 140static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
 141        .bustype        = BUS_SPI,
 142        .write          = cyttsp_spi_write_block_data,
 143        .read           = cyttsp_spi_read_block_data,
 144};
 145
 146static int cyttsp4_spi_probe(struct spi_device *spi)
 147{
 148        struct cyttsp4 *ts;
 149        int error;
 150
 151        /* Set up SPI*/
 152        spi->bits_per_word = CY_SPI_BITS_PER_WORD;
 153        spi->mode = SPI_MODE_0;
 154        error = spi_setup(spi);
 155        if (error < 0) {
 156                dev_err(&spi->dev, "%s: SPI setup error %d\n",
 157                        __func__, error);
 158                return error;
 159        }
 160
 161        ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
 162                          CY_SPI_DATA_BUF_SIZE);
 163
 164        return PTR_ERR_OR_ZERO(ts);
 165}
 166
 167static int cyttsp4_spi_remove(struct spi_device *spi)
 168{
 169        struct cyttsp4 *ts = spi_get_drvdata(spi);
 170        cyttsp4_remove(ts);
 171
 172        return 0;
 173}
 174
 175static struct spi_driver cyttsp4_spi_driver = {
 176        .driver = {
 177                .name   = CYTTSP4_SPI_NAME,
 178                .pm     = &cyttsp4_pm_ops,
 179        },
 180        .probe  = cyttsp4_spi_probe,
 181        .remove = cyttsp4_spi_remove,
 182};
 183
 184module_spi_driver(cyttsp4_spi_driver);
 185
 186MODULE_LICENSE("GPL");
 187MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
 188MODULE_AUTHOR("Cypress");
 189MODULE_ALIAS("spi:cyttsp4");
 190