diff options
author | Wendly Li <wendlyli@google.com> | 2021-12-29 08:25:53 +0000 |
---|---|---|
committer | Wendly Li <wendlyli@google.com> | 2022-01-21 03:51:40 +0000 |
commit | f4cbd1e784f777c544763bb0e2bdb65ad5c685cf (patch) | |
tree | b46d9dba8ae66c85da61754fbdb3b9ce279c3789 /goodix_brl_spi.c | |
parent | aa0a75aa6af4b4513db1719e841973d3a50f59c3 (diff) | |
download | goodix_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.c | 308 |
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); +} |