blob: 698ee6c2acf900370fcb6ee32b793741d38b316d [file] [log] [blame] [edit]
/*
* Goodix Touchscreen Driver
* Copyright (C) 2020 - 2021 Goodix, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be a reference
* to you, when you are integrating the GOODiX's CTP IC into your system,
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#ifdef CONFIG_GOOG_TOUCH_INTERFACE
#include <goog_touch_interface.h>
#endif
#include "goodix_ts_core.h"
#define TS_DRIVER_NAME "gtx8_spi"
#define SPI_TRANS_PREFIX_LEN 1
#define REGISTER_WIDTH 4
#define SPI_READ_DUMMY_LEN 4
#define SPI_READ_PREFIX_LEN \
(SPI_TRANS_PREFIX_LEN + REGISTER_WIDTH + SPI_READ_DUMMY_LEN)
#define SPI_WRITE_PREFIX_LEN (SPI_TRANS_PREFIX_LEN + REGISTER_WIDTH)
#define SPI_PREALLOC_RX_BUF_SIZE 4096 + SPI_READ_PREFIX_LEN
#define SPI_PREALLOC_TX_BUF_SIZE 4096 + SPI_WRITE_PREFIX_LEN
#define SPI_WRITE_FLAG 0xF0
#define SPI_READ_FLAG 0xF1
/**
* goodix_spi_read_bra- read device register through spi bus
* @dev: pointer to device data
* @addr: register address
* @data: read buffer
* @len: bytes to read
* return: 0 - read ok, < 0 - spi transter error
*/
static int goodix_spi_read_bra(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
struct goodix_ts_core *cd = dev_get_drvdata(dev);
struct goodix_bus_interface *bus = cd->bus;
u8 *rx_buf = NULL;
u8 *tx_buf = NULL;
struct spi_transfer xfers;
struct spi_message spi_msg;
int ret = 0;
int buf_len = SPI_READ_PREFIX_LEN + len;
mutex_lock(&bus->mutex);
if (buf_len <= SPI_PREALLOC_RX_BUF_SIZE &&
buf_len <= SPI_PREALLOC_TX_BUF_SIZE) {
rx_buf = bus->rx_buf;
tx_buf = bus->tx_buf;
memset(tx_buf, 0, buf_len);
} else {
rx_buf = kzalloc(buf_len, GFP_KERNEL);
if (!rx_buf) {
ts_err("alloc rx_buf failed, size:%d", buf_len);
ret = -ENOMEM;
goto err_alloc_rx_buf;
}
tx_buf = kzalloc(buf_len, GFP_KERNEL);
if (!tx_buf) {
ts_err("alloc tx_buf failed, size:%d", buf_len);
ret = -ENOMEM;
goto err_alloc_tx_buf;
}
}
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
/*spi_read tx_buf format: 0xF1 + addr(4bytes) + data*/
tx_buf[0] = SPI_READ_FLAG;
tx_buf[1] = (addr >> 24) & 0xFF;
tx_buf[2] = (addr >> 16) & 0xFF;
tx_buf[3] = (addr >> 8) & 0xFF;
tx_buf[4] = addr & 0xFF;
tx_buf[5] = 0xFF;
tx_buf[6] = 0xFF;
tx_buf[7] = 0xFF;
tx_buf[8] = 0xFF;
xfers.tx_buf = tx_buf;
xfers.rx_buf = rx_buf;
xfers.len = buf_len;
xfers.cs_change = 0;
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
if (ret < 0) {
ts_err("spi transfer error:%d", ret);
goto err_spi_transfer;
}
memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN], len);
err_spi_transfer:
if (tx_buf != bus->tx_buf)
kfree(tx_buf);
err_alloc_tx_buf:
if (rx_buf != bus->rx_buf)
kfree(rx_buf);
err_alloc_rx_buf:
mutex_unlock(&bus->mutex);
return ret;
}
static int goodix_spi_read(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
struct goodix_ts_core *cd = dev_get_drvdata(dev);
struct goodix_bus_interface *bus = cd->bus;
u8 *rx_buf = NULL;
u8 *tx_buf = NULL;
struct spi_transfer xfers;
struct spi_message spi_msg;
int ret = 0;
int buf_len = SPI_READ_PREFIX_LEN - 1 + len;
if (bus->dma_mode_enabled && buf_len >= 64)
buf_len = ALIGN(buf_len, 4);
mutex_lock(&bus->mutex);
if (buf_len <= SPI_PREALLOC_RX_BUF_SIZE &&
buf_len <= SPI_PREALLOC_TX_BUF_SIZE) {
rx_buf = bus->rx_buf;
tx_buf = bus->tx_buf;
memset(tx_buf, 0, buf_len);
} else {
rx_buf = kzalloc(buf_len, GFP_KERNEL);
if (!rx_buf) {
ts_err("alloc rx_buf failed, size:%d", buf_len);
ret = -ENOMEM;
goto err_alloc_rx_buf;
}
tx_buf = kzalloc(buf_len, GFP_KERNEL);
if (!tx_buf) {
ts_err("alloc tx_buf failed, size:%d", buf_len);
ret = -ENOMEM;
goto err_alloc_tx_buf;
}
}
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
/*spi_read tx_buf format: 0xF1 + addr(4bytes) + data*/
tx_buf[0] = SPI_READ_FLAG;
tx_buf[1] = (addr >> 24) & 0xFF;
tx_buf[2] = (addr >> 16) & 0xFF;
tx_buf[3] = (addr >> 8) & 0xFF;
tx_buf[4] = addr & 0xFF;
tx_buf[5] = 0xFF;
tx_buf[6] = 0xFF;
tx_buf[7] = 0xFF;
xfers.tx_buf = tx_buf;
xfers.rx_buf = rx_buf;
xfers.len = buf_len;
xfers.cs_change = 0;
if (bus->dma_mode_enabled)
xfers.bits_per_word = buf_len >= 64 ? 32 : 8;
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
if (ret < 0) {
ts_err("spi transfer error:%d", ret);
goto err_spi_transfer;
}
memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN - 1], len);
err_spi_transfer:
if (tx_buf != bus->tx_buf)
kfree(tx_buf);
err_alloc_tx_buf:
if (rx_buf != bus->rx_buf)
kfree(rx_buf);
err_alloc_rx_buf:
mutex_unlock(&bus->mutex);
return ret;
}
/* [GOOG]
* This SPI transaction will direct read into `struct goodix_rx_package`.
* And, the package are comprised of `SPI prefix header` + `data`.
*/
static int goodix_spi_read_fast(struct device *dev, unsigned int addr,
struct goodix_rx_package *package, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
struct goodix_ts_core *cd = dev_get_drvdata(dev);
struct goodix_bus_interface *bus = cd->bus;
u8 *tx_buf = NULL;
struct spi_transfer xfers;
struct spi_message spi_msg;
int ret = 0;
int buf_len = SPI_READ_PREFIX_LEN - 1 + len;
if (bus->dma_mode_enabled && buf_len >= 64)
buf_len = ALIGN(buf_len, 4);
if (buf_len <= SPI_PREALLOC_TX_BUF_SIZE) {
tx_buf = bus->tx_buf;
} else {
tx_buf = kzalloc(buf_len, GFP_KERNEL);
if (!tx_buf) {
ts_err("alloc tx_buf failed, size:%d", buf_len);
return -ENOMEM;
}
}
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
mutex_lock(&bus->mutex);
/*spi_read tx_buf format: 0xF1 + addr(4bytes) + data*/
tx_buf[0] = SPI_READ_FLAG;
tx_buf[1] = (addr >> 24) & 0xFF;
tx_buf[2] = (addr >> 16) & 0xFF;
tx_buf[3] = (addr >> 8) & 0xFF;
tx_buf[4] = addr & 0xFF;
tx_buf[5] = 0xFF;
tx_buf[6] = 0xFF;
tx_buf[7] = 0xFF;
xfers.tx_buf = tx_buf;
xfers.rx_buf = package->header;
xfers.len = buf_len;
xfers.cs_change = 0;
if (bus->dma_mode_enabled)
xfers.bits_per_word = buf_len >= 64 ? 32 : 8;
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
mutex_unlock(&bus->mutex);
if (ret < 0) {
ts_err("spi transfer error:%d", ret);
goto err_spi_transfer;
}
err_spi_transfer:
if (tx_buf != bus->tx_buf)
kfree(tx_buf);
return ret;
}
/**
* goodix_spi_write- write device register through spi bus
* @dev: pointer to device data
* @addr: register address
* @data: write buffer
* @len: bytes to write
* return: 0 - write ok; < 0 - spi transter error.
*/
static int goodix_spi_write(struct device *dev, unsigned int addr,
unsigned char *data, unsigned int len)
{
struct spi_device *spi = to_spi_device(dev);
struct goodix_ts_core *cd = dev_get_drvdata(dev);
struct goodix_bus_interface *bus = cd->bus;
u8 *tx_buf = NULL;
struct spi_transfer xfers;
struct spi_message spi_msg;
int ret = 0;
int buf_len = SPI_WRITE_PREFIX_LEN + len;
if (bus->dma_mode_enabled && buf_len >= 64)
buf_len = ALIGN(buf_len, 4);
if (buf_len <= SPI_PREALLOC_TX_BUF_SIZE) {
tx_buf = bus->tx_buf;
} else {
tx_buf = kzalloc(buf_len, GFP_KERNEL);
if (!tx_buf) {
ts_err("alloc tx_buf failed, size:%d", buf_len);
return -ENOMEM;
}
}
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
mutex_lock(&bus->mutex);
tx_buf[0] = SPI_WRITE_FLAG;
tx_buf[1] = (addr >> 24) & 0xFF;
tx_buf[2] = (addr >> 16) & 0xFF;
tx_buf[3] = (addr >> 8) & 0xFF;
tx_buf[4] = addr & 0xFF;
memcpy(&tx_buf[SPI_WRITE_PREFIX_LEN], data, len);
xfers.tx_buf = tx_buf;
xfers.len = buf_len;
xfers.cs_change = 0;
if (bus->dma_mode_enabled)
xfers.bits_per_word = buf_len >= 64 ? 32 : 8;
spi_message_add_tail(&xfers, &spi_msg);
ret = spi_sync(spi, &spi_msg);
mutex_unlock(&bus->mutex);
if (ret < 0)
ts_err("spi transfer error:%d", ret);
if (tx_buf != bus->tx_buf)
kfree(tx_buf);
return ret;
}
static int goodix_spi_probe(struct spi_device *spi)
{
struct goodix_device_resource *dev_res;
int ret = 0;
ts_info("%s: goodix spi probe in", __func__);
/* init spi_device */
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
spi->rt = true; /* [GOOG] */
ret = spi_setup(spi);
if (ret) {
ts_err("failed set spi mode, %d", ret);
return ret;
}
dev_res = kzalloc(sizeof(*dev_res), GFP_KERNEL);
if (!dev_res)
return -ENOMEM;
/* get ic type */
ret = goodix_get_ic_type(spi->dev.of_node, &dev_res->bus);
if (ret < 0)
goto err_get_ic_type;
dev_res->bus.bus_type = GOODIX_BUS_TYPE_SPI;
dev_res->bus.dev = &spi->dev;
if (dev_res->bus.ic_type == IC_TYPE_BERLIN_A) {
dev_res->bus.read = goodix_spi_read_bra;
} else {
dev_res->bus.read = goodix_spi_read;
dev_res->bus.read_fast = goodix_spi_read_fast;
}
dev_res->bus.write = goodix_spi_write;
/* [GOOG]
* Move goodix_device_register() after `dev_res->bus.dev` assigned.
* This will help to set the `struct device *dev` early.
*/
goodix_device_register(dev_res);
dev_res->bus.rx_buf = kzalloc(SPI_PREALLOC_RX_BUF_SIZE, GFP_KERNEL);
dev_res->bus.tx_buf = kzalloc(SPI_PREALLOC_TX_BUF_SIZE, GFP_KERNEL);
if (!dev_res->bus.rx_buf || !dev_res->bus.tx_buf) {
ret = -ENOMEM;
goto err_pdev;
}
/*~[GOOG] */
mutex_init(&dev_res->bus.mutex);
dev_res->bus.dma_mode_enabled = false;
#ifdef CONFIG_GOOG_TOUCH_INTERFACE
dev_res->bus.dma_mode_enabled = goog_check_spi_dma_enabled(spi);
ts_info("dma_mode: %s\n", dev_res->bus.dma_mode_enabled ? "enabled" : "disabled");
#endif
// platform device init
dev_res->pdev.name = GOODIX_CORE_DRIVER_NAME;
dev_res->pdev.id = dev_res->id;
dev_res->pdev.num_resources = 0;
/* register platform device, then the goodix_ts_core
* module will probe the touch device.
*/
ret = platform_device_register(&dev_res->pdev);
if (ret) {
ts_err("failed register goodix platform device, %d", ret);
goto err_pdev;
}
ts_info("spi probe out");
return 0;
err_pdev:
kfree(dev_res->bus.rx_buf);
kfree(dev_res->bus.tx_buf);
err_get_ic_type:
kfree(dev_res);
ts_info("spi probe out, %d", ret);
return ret;
}
static int goodix_spi_remove(struct spi_device *spi)
{
/* goodix_ts_core_exit() will unregister device(s) */
// platform_device_unregister(dev_res->pdev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id spi_matches[] = {
{
.compatible = "goodix,brl-a",
},
{
.compatible = "goodix,brl-b",
},
{
.compatible = "goodix,brl-b,gt7986",
},
{
.compatible = "goodix,brl-d",
},
{
.compatible = "goodix,nottingham",
},
{},
};
#endif
static const struct spi_device_id spi_id_table[] = {
{ TS_DRIVER_NAME, 0 },
{},
};
static struct spi_driver goodix_spi_driver = {
.driver = {
.name = TS_DRIVER_NAME,
//.owner = THIS_MODULE,
.of_match_table = spi_matches,
},
.id_table = spi_id_table,
.probe = goodix_spi_probe,
.remove = goodix_spi_remove,
};
int goodix_spi_bus_init(void)
{
ts_info("Goodix spi driver init");
return spi_register_driver(&goodix_spi_driver);
}
void goodix_spi_bus_exit(void)
{
ts_info("Goodix spi driver exit");
spi_unregister_driver(&goodix_spi_driver);
}