summaryrefslogtreecommitdiff
path: root/goodix_brl_spi.c
diff options
context:
space:
mode:
authorWendly Li <wendlyli@google.com>2021-12-29 08:25:53 +0000
committerWendly Li <wendlyli@google.com>2022-01-21 03:51:40 +0000
commitf4cbd1e784f777c544763bb0e2bdb65ad5c685cf (patch)
treeb46d9dba8ae66c85da61754fbdb3b9ce279c3789 /goodix_brl_spi.c
parentaa0a75aa6af4b4513db1719e841973d3a50f59c3 (diff)
downloadgoodix_touch-f4cbd1e784f777c544763bb0e2bdb65ad5c685cf.tar.gz
Initial the driver from the original vender code
BYPASS_INCLUSIVE_LANGUAGE_REASON=master and slave are stardand of SPI Bug: 214018056 Bug: 214118475 Change-Id: Ib1e7bbdca701fe852f665ee2986824d71d5eebe2 Signed-off-by: Wendly Li <wendlyli@google.com>
Diffstat (limited to 'goodix_brl_spi.c')
-rw-r--r--goodix_brl_spi.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/goodix_brl_spi.c b/goodix_brl_spi.c
new file mode 100644
index 0000000..8f53776
--- /dev/null
+++ b/goodix_brl_spi.c
@@ -0,0 +1,308 @@
+/*
+ * 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>
+
+#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_WRITE_FLAG 0xF0
+#define SPI_READ_FLAG 0xF1
+
+static struct platform_device *goodix_pdev;
+struct goodix_bus_interface goodix_spi_bus;
+
+/**
+ * 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);
+ u8 *rx_buf = NULL;
+ u8 *tx_buf = NULL;
+ struct spi_transfer xfers;
+ struct spi_message spi_msg;
+ int ret = 0;
+
+ rx_buf = kzalloc(SPI_READ_PREFIX_LEN + len, GFP_KERNEL);
+ tx_buf = kzalloc(SPI_READ_PREFIX_LEN + len, GFP_KERNEL);
+ if (!rx_buf || !tx_buf) {
+ ts_err("alloc tx/rx_buf failed, size:%d",
+ SPI_READ_PREFIX_LEN + len);
+ return -ENOMEM;
+ }
+
+ 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 = SPI_READ_PREFIX_LEN + 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 exit;
+ }
+ memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN], len);
+
+exit:
+ kfree(rx_buf);
+ kfree(tx_buf);
+ 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);
+ u8 *rx_buf = NULL;
+ u8 *tx_buf = NULL;
+ struct spi_transfer xfers;
+ struct spi_message spi_msg;
+ int ret = 0;
+
+ rx_buf = kzalloc(SPI_READ_PREFIX_LEN - 1 + len, GFP_KERNEL);
+ tx_buf = kzalloc(SPI_READ_PREFIX_LEN - 1 + len, GFP_KERNEL);
+ if (!rx_buf || !tx_buf) {
+ ts_err("alloc tx/rx_buf failed, size:%d",
+ SPI_READ_PREFIX_LEN - 1 + len);
+ return -ENOMEM;
+ }
+
+ 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 = SPI_READ_PREFIX_LEN - 1 + 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 exit;
+ }
+ memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN - 1], len);
+
+exit:
+ kfree(rx_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);
+ u8 *tx_buf = NULL;
+ struct spi_transfer xfers;
+ struct spi_message spi_msg;
+ int ret = 0;
+
+ tx_buf = kzalloc(SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL);
+ if (!tx_buf) {
+ ts_err("alloc tx_buf failed, size:%d",
+ SPI_WRITE_PREFIX_LEN + len);
+ return -ENOMEM;
+ }
+
+ spi_message_init(&spi_msg);
+ memset(&xfers, 0, sizeof(xfers));
+
+ 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 = SPI_WRITE_PREFIX_LEN + 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);
+
+ kfree(tx_buf);
+ return ret;
+}
+
+static void goodix_pdev_release(struct device *dev)
+{
+ ts_info("goodix pdev released");
+ kfree(goodix_pdev);
+}
+
+static int goodix_spi_probe(struct spi_device *spi)
+{
+ int ret = 0;
+
+ ts_info("goodix spi probe in");
+
+ /* init spi_device */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+
+ ret = spi_setup(spi);
+ if (ret) {
+ ts_err("failed set spi mode, %d", ret);
+ return ret;
+ }
+
+ /* get ic type */
+ ret = goodix_get_ic_type(spi->dev.of_node);
+ if (ret < 0)
+ return ret;
+
+ goodix_spi_bus.ic_type = ret;
+ goodix_spi_bus.bus_type = GOODIX_BUS_TYPE_SPI;
+ goodix_spi_bus.dev = &spi->dev;
+ if (goodix_spi_bus.ic_type == IC_TYPE_BERLIN_A)
+ goodix_spi_bus.read = goodix_spi_read_bra;
+ else
+ goodix_spi_bus.read = goodix_spi_read;
+ goodix_spi_bus.write = goodix_spi_write;
+ /* ts core device */
+ goodix_pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+ if (!goodix_pdev)
+ return -ENOMEM;
+
+ goodix_pdev->name = GOODIX_CORE_DRIVER_NAME;
+ goodix_pdev->id = 0;
+ goodix_pdev->num_resources = 0;
+ /*
+ * you can find this platform dev in
+ * /sys/devices/platform/goodix_ts.0
+ * goodix_pdev->dev.parent = &client->dev;
+ */
+ goodix_pdev->dev.platform_data = &goodix_spi_bus;
+ goodix_pdev->dev.release = goodix_pdev_release;
+
+ /* register platform device, then the goodix_ts_core
+ * module will probe the touch device.
+ */
+ ret = platform_device_register(goodix_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(goodix_pdev);
+ goodix_pdev = NULL;
+ ts_info("spi probe out, %d", ret);
+ return ret;
+}
+
+static int goodix_spi_remove(struct spi_device *spi)
+{
+ platform_device_unregister(goodix_pdev);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id spi_matches[] = {
+ {
+ .compatible = "goodix,gt9897S",
+ },
+ {
+ .compatible = "goodix,gt9897T",
+ },
+ {
+ .compatible = "goodix,gt9966S",
+ },
+ {
+ .compatible = "goodix,gt9916S",
+ },
+ {},
+};
+#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);
+}