linux/drivers/input/touchscreen/edt-ft5x06.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2012 Simon Budig, <[email protected]>
 * Daniel Wagener <[email protected]> (M09 firmware support)
 * Lothar Waßmann <[email protected]> (DT support)
 * Dario Binacchi <[email protected]> (regmap support)
 */

/*
 * This is a driver for the EDT "Polytouch" family of touch controllers
 * based on the FocalTech FT5x06 line of chips.
 *
 * Development of this driver has been sponsored by Glyn:
 *    http://www.glyn.com/Products/Displays
 */

#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/ratelimit.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include <linux/unaligned.h>

#define WORK_REGISTER_THRESHOLD
#define WORK_REGISTER_REPORT_RATE
#define WORK_REGISTER_GAIN
#define WORK_REGISTER_OFFSET
#define WORK_REGISTER_NUM_X
#define WORK_REGISTER_NUM_Y

#define PMOD_REGISTER_ACTIVE
#define PMOD_REGISTER_HIBERNATE

#define M09_REGISTER_THRESHOLD
#define M09_REGISTER_GAIN
#define M09_REGISTER_OFFSET
#define M09_REGISTER_NUM_X
#define M09_REGISTER_NUM_Y

#define M12_REGISTER_REPORT_RATE

#define EV_REGISTER_THRESHOLD
#define EV_REGISTER_GAIN
#define EV_REGISTER_OFFSET_Y
#define EV_REGISTER_OFFSET_X

#define NO_REGISTER

#define WORK_REGISTER_OPMODE
#define FACTORY_REGISTER_OPMODE
#define PMOD_REGISTER_OPMODE

#define TOUCH_EVENT_DOWN
#define TOUCH_EVENT_UP
#define TOUCH_EVENT_ON
#define TOUCH_EVENT_RESERVED

#define EDT_NAME_LEN
#define EDT_SWITCH_MODE_RETRIES
#define EDT_SWITCH_MODE_DELAY
#define EDT_RAW_DATA_RETRIES
#define EDT_RAW_DATA_DELAY

#define EDT_DEFAULT_NUM_X
#define EDT_DEFAULT_NUM_Y

#define M06_REG_CMD(factory)
#define M06_REG_ADDR(factory, addr)

enum edt_pmode {};

enum edt_ver {};

struct edt_reg_addr {};

struct edt_ft5x06_ts_data {};

struct edt_i2c_chip_data {};

static const struct regmap_config edt_ft5x06_i2c_regmap_config =;

static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
				    u8 *buf, int buflen)
{}

static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size,
			    void *val_buf, size_t val_size)
{}

static int edt_M06_i2c_write(void *context, const void *data, size_t count)
{}

static const struct regmap_config edt_M06_i2c_regmap_config =;

static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
{}

struct edt_ft5x06_attribute {};

#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_ev,		\
		_limit_low, _limit_high)

static ssize_t edt_ft5x06_setting_show(struct device *dev,
				       struct device_attribute *dattr,
				       char *buf)
{}

static ssize_t edt_ft5x06_setting_store(struct device *dev,
					struct device_attribute *dattr,
					const char *buf, size_t count)
{}

/* m06, m09: range 0-31, m12: range 0-5 */
static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
		M09_REGISTER_GAIN, EV_REGISTER_GAIN, 0, 31);
/* m06, m09: range 0-31, m12: range 0-16 */
static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
		M09_REGISTER_OFFSET, NO_REGISTER, 0, 31);
/* m06, m09, m12: no supported, ev_ft: range 0-80 */
static EDT_ATTR(offset_x, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
		EV_REGISTER_OFFSET_X, 0, 80);
/* m06, m09, m12: no supported, ev_ft: range 0-80 */
static EDT_ATTR(offset_y, S_IWUSR | S_IRUGO, NO_REGISTER, NO_REGISTER,
		EV_REGISTER_OFFSET_Y, 0, 80);
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
		M09_REGISTER_THRESHOLD, EV_REGISTER_THRESHOLD, 0, 255);
/* m06: range 3 to 14, m12: range 1 to 255 */
static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
		M12_REGISTER_REPORT_RATE, NO_REGISTER, 0, 255);

static ssize_t model_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{}

static DEVICE_ATTR_RO(model);

static ssize_t fw_version_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{}

static DEVICE_ATTR_RO(fw_version);

/* m06 only */
static ssize_t header_errors_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
{}

static DEVICE_ATTR_RO(header_errors);

/* m06 only */
static ssize_t crc_errors_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
{}

static DEVICE_ATTR_RO(crc_errors);

static struct attribute *edt_ft5x06_attrs[] =;
ATTRIBUTE_GROUPS();

static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata)
{}

#ifdef CONFIG_DEBUG_FS
static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
{}

static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
{}

static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode)
{
	struct edt_ft5x06_ts_data *tsdata = data;

	*mode = tsdata->factory_mode;

	return 0;
};

static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
{
	struct edt_ft5x06_ts_data *tsdata = data;
	int retval = 0;

	if (mode > 1)
		return -ERANGE;

	mutex_lock(&tsdata->mutex);

	if (mode != tsdata->factory_mode) {
		retval = mode ? edt_ft5x06_factory_mode(tsdata) :
				edt_ft5x06_work_mode(tsdata);
	}

	mutex_unlock(&tsdata->mutex);

	return retval;
};

DEFINE_SIMPLE_ATTRIBUTE();

static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
						char __user *buf, size_t count,
						loff_t *off)
{
	struct edt_ft5x06_ts_data *tsdata = file->private_data;
	struct i2c_client *client = tsdata->client;
	int retries  = EDT_RAW_DATA_RETRIES;
	unsigned int val;
	int i, error;
	size_t read = 0;
	int colbytes;
	u8 *rdbuf;

	if (*off < 0 || *off >= tsdata->raw_bufsize)
		return 0;

	mutex_lock(&tsdata->mutex);

	if (!tsdata->factory_mode || !tsdata->raw_buffer) {
		error = -EIO;
		goto out;
	}

	error = regmap_write(tsdata->regmap, 0x08, 0x01);
	if (error) {
		dev_err(&client->dev,
			"failed to write 0x08 register, error %d\n", error);
		goto out;
	}

	do {
		usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100);
		error = regmap_read(tsdata->regmap, 0x08, &val);
		if (error) {
			dev_err(&client->dev,
				"failed to read 0x08 register, error %d\n",
				error);
			goto out;
		}

		if (val == 1)
			break;
	} while (--retries > 0);

	if (retries == 0) {
		dev_err(&client->dev,
			"timed out waiting for register to settle\n");
		error = -ETIMEDOUT;
		goto out;
	}

	rdbuf = tsdata->raw_buffer;
	colbytes = tsdata->num_y * sizeof(u16);

	for (i = 0; i < tsdata->num_x; i++) {
		rdbuf[0] = i;  /* column index */
		error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes);
		if (error)
			goto out;

		rdbuf += colbytes;
	}

	read = min_t(size_t, count, tsdata->raw_bufsize - *off);
	if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) {
		error = -EFAULT;
		goto out;
	}

	*off += read;
out:
	mutex_unlock(&tsdata->mutex);
	return error ?: read;
};

static const struct file_operations debugfs_raw_data_fops =;

static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
					  const char *debugfs_name)
{}

static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{}

#else

static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
{
	return -ENOSYS;
}

static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
					  const char *debugfs_name)
{
}

static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
}

#endif /* CONFIG_DEBUGFS */

static int edt_ft5x06_ts_identify(struct i2c_client *client,
				  struct edt_ft5x06_ts_data *tsdata)
{}

static void edt_ft5x06_ts_get_defaults(struct device *dev,
				       struct edt_ft5x06_ts_data *tsdata)
{}

static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
{}

static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata)
{}

static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
{}

static void edt_ft5x06_exit_regmap(void *arg)
{}

static void edt_ft5x06_disable_regulators(void *arg)
{}

static int edt_ft5x06_ts_probe(struct i2c_client *client)
{}

static void edt_ft5x06_ts_remove(struct i2c_client *client)
{}

static int edt_ft5x06_ts_suspend(struct device *dev)
{}

static int edt_ft5x06_ts_resume(struct device *dev)
{}

static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
				edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);

static const struct edt_i2c_chip_data edt_ft5x06_data =;

static const struct edt_i2c_chip_data edt_ft5452_data =;

static const struct edt_i2c_chip_data edt_ft5506_data =;

static const struct edt_i2c_chip_data edt_ft6236_data =;

static const struct edt_i2c_chip_data edt_ft8201_data =;

static const struct edt_i2c_chip_data edt_ft8719_data =;

static const struct i2c_device_id edt_ft5x06_ts_id[] =;
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);

static const struct of_device_id edt_ft5x06_of_match[] =;
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);

static struct i2c_driver edt_ft5x06_ts_driver =;

module_i2c_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();