162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AD714X CapTouch Programmable Controller driver (SPI bus)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2009-2011 Analog Devices Inc.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/input.h>	/* BUS_SPI */
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/spi/spi.h>
1162306a36Sopenharmony_ci#include <linux/pm.h>
1262306a36Sopenharmony_ci#include <linux/types.h>
1362306a36Sopenharmony_ci#include "ad714x.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define AD714x_SPI_CMD_PREFIX      0xE000   /* bits 15:11 */
1662306a36Sopenharmony_ci#define AD714x_SPI_READ            BIT(10)
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic int ad714x_spi_read(struct ad714x_chip *chip,
1962306a36Sopenharmony_ci			   unsigned short reg, unsigned short *data, size_t len)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct spi_device *spi = to_spi_device(chip->dev);
2262306a36Sopenharmony_ci	struct spi_message message;
2362306a36Sopenharmony_ci	struct spi_transfer xfer[2];
2462306a36Sopenharmony_ci	int i;
2562306a36Sopenharmony_ci	int error;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	spi_message_init(&message);
2862306a36Sopenharmony_ci	memset(xfer, 0, sizeof(xfer));
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX |
3162306a36Sopenharmony_ci					AD714x_SPI_READ | reg);
3262306a36Sopenharmony_ci	xfer[0].tx_buf = &chip->xfer_buf[0];
3362306a36Sopenharmony_ci	xfer[0].len = sizeof(chip->xfer_buf[0]);
3462306a36Sopenharmony_ci	spi_message_add_tail(&xfer[0], &message);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	xfer[1].rx_buf = &chip->xfer_buf[1];
3762306a36Sopenharmony_ci	xfer[1].len = sizeof(chip->xfer_buf[1]) * len;
3862306a36Sopenharmony_ci	spi_message_add_tail(&xfer[1], &message);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	error = spi_sync(spi, &message);
4162306a36Sopenharmony_ci	if (unlikely(error)) {
4262306a36Sopenharmony_ci		dev_err(chip->dev, "SPI read error: %d\n", error);
4362306a36Sopenharmony_ci		return error;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	for (i = 0; i < len; i++)
4762306a36Sopenharmony_ci		data[i] = be16_to_cpu(chip->xfer_buf[i + 1]);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int ad714x_spi_write(struct ad714x_chip *chip,
5362306a36Sopenharmony_ci			    unsigned short reg, unsigned short data)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct spi_device *spi = to_spi_device(chip->dev);
5662306a36Sopenharmony_ci	int error;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX | reg);
5962306a36Sopenharmony_ci	chip->xfer_buf[1] = cpu_to_be16(data);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	error = spi_write(spi, (u8 *)chip->xfer_buf,
6262306a36Sopenharmony_ci			  2 * sizeof(*chip->xfer_buf));
6362306a36Sopenharmony_ci	if (unlikely(error)) {
6462306a36Sopenharmony_ci		dev_err(chip->dev, "SPI write error: %d\n", error);
6562306a36Sopenharmony_ci		return error;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int ad714x_spi_probe(struct spi_device *spi)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct ad714x_chip *chip;
7462306a36Sopenharmony_ci	int err;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	spi->bits_per_word = 8;
7762306a36Sopenharmony_ci	err = spi_setup(spi);
7862306a36Sopenharmony_ci	if (err < 0)
7962306a36Sopenharmony_ci		return err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
8262306a36Sopenharmony_ci			    ad714x_spi_read, ad714x_spi_write);
8362306a36Sopenharmony_ci	if (IS_ERR(chip))
8462306a36Sopenharmony_ci		return PTR_ERR(chip);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	spi_set_drvdata(spi, chip);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic struct spi_driver ad714x_spi_driver = {
9262306a36Sopenharmony_ci	.driver = {
9362306a36Sopenharmony_ci		.name	= "ad714x_captouch",
9462306a36Sopenharmony_ci		.pm	= pm_sleep_ptr(&ad714x_pm),
9562306a36Sopenharmony_ci	},
9662306a36Sopenharmony_ci	.probe		= ad714x_spi_probe,
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cimodule_spi_driver(ad714x_spi_driver);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver");
10262306a36Sopenharmony_ciMODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
10362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
104