18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG
48c2ecf20Sopenharmony_ci *	Nikolaus Schaller <hns@goldelico.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/i2c.h>
88c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
98c2ecf20Sopenharmony_ci#include "tsc2007.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistruct tsc2007_iio {
128c2ecf20Sopenharmony_ci	struct tsc2007 *ts;
138c2ecf20Sopenharmony_ci};
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define TSC2007_CHAN_IIO(_chan, _name, _type, _chan_info) \
168c2ecf20Sopenharmony_ci{ \
178c2ecf20Sopenharmony_ci	.datasheet_name = _name, \
188c2ecf20Sopenharmony_ci	.type = _type, \
198c2ecf20Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
208c2ecf20Sopenharmony_ci			BIT(_chan_info), \
218c2ecf20Sopenharmony_ci	.indexed = 1, \
228c2ecf20Sopenharmony_ci	.channel = _chan, \
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic const struct iio_chan_spec tsc2007_iio_channel[] = {
268c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(0, "x", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
278c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(1, "y", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
288c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(2, "z1", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
298c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(3, "z2", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
308c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(4, "adc", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
318c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(5, "rt", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), /* Ohms? */
328c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(6, "pen", IIO_PRESSURE, IIO_CHAN_INFO_RAW),
338c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(7, "temp0", IIO_TEMP, IIO_CHAN_INFO_RAW),
348c2ecf20Sopenharmony_ci	TSC2007_CHAN_IIO(8, "temp1", IIO_TEMP, IIO_CHAN_INFO_RAW),
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int tsc2007_read_raw(struct iio_dev *indio_dev,
388c2ecf20Sopenharmony_ci			    struct iio_chan_spec const *chan,
398c2ecf20Sopenharmony_ci			    int *val, int *val2, long mask)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct tsc2007_iio *iio = iio_priv(indio_dev);
428c2ecf20Sopenharmony_ci	struct tsc2007 *tsc = iio->ts;
438c2ecf20Sopenharmony_ci	int adc_chan = chan->channel;
448c2ecf20Sopenharmony_ci	int ret = 0;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel))
478c2ecf20Sopenharmony_ci		return -EINVAL;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (mask != IIO_CHAN_INFO_RAW)
508c2ecf20Sopenharmony_ci		return -EINVAL;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	mutex_lock(&tsc->mlock);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	switch (chan->channel) {
558c2ecf20Sopenharmony_ci	case 0:
568c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc, READ_X);
578c2ecf20Sopenharmony_ci		break;
588c2ecf20Sopenharmony_ci	case 1:
598c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc, READ_Y);
608c2ecf20Sopenharmony_ci		break;
618c2ecf20Sopenharmony_ci	case 2:
628c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc, READ_Z1);
638c2ecf20Sopenharmony_ci		break;
648c2ecf20Sopenharmony_ci	case 3:
658c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc, READ_Z2);
668c2ecf20Sopenharmony_ci		break;
678c2ecf20Sopenharmony_ci	case 4:
688c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc, (ADC_ON_12BIT | TSC2007_MEASURE_AUX));
698c2ecf20Sopenharmony_ci		break;
708c2ecf20Sopenharmony_ci	case 5: {
718c2ecf20Sopenharmony_ci		struct ts_event tc;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci		tc.x = tsc2007_xfer(tsc, READ_X);
748c2ecf20Sopenharmony_ci		tc.z1 = tsc2007_xfer(tsc, READ_Z1);
758c2ecf20Sopenharmony_ci		tc.z2 = tsc2007_xfer(tsc, READ_Z2);
768c2ecf20Sopenharmony_ci		*val = tsc2007_calculate_resistance(tsc, &tc);
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	case 6:
808c2ecf20Sopenharmony_ci		*val = tsc2007_is_pen_down(tsc);
818c2ecf20Sopenharmony_ci		break;
828c2ecf20Sopenharmony_ci	case 7:
838c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc,
848c2ecf20Sopenharmony_ci				    (ADC_ON_12BIT | TSC2007_MEASURE_TEMP0));
858c2ecf20Sopenharmony_ci		break;
868c2ecf20Sopenharmony_ci	case 8:
878c2ecf20Sopenharmony_ci		*val = tsc2007_xfer(tsc,
888c2ecf20Sopenharmony_ci				    (ADC_ON_12BIT | TSC2007_MEASURE_TEMP1));
898c2ecf20Sopenharmony_ci		break;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* Prepare for next touch reading - power down ADC, enable PENIRQ */
938c2ecf20Sopenharmony_ci	tsc2007_xfer(tsc, PWRDOWN);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	mutex_unlock(&tsc->mlock);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	ret = IIO_VAL_INT;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return ret;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic const struct iio_info tsc2007_iio_info = {
1038c2ecf20Sopenharmony_ci	.read_raw = tsc2007_read_raw,
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciint tsc2007_iio_configure(struct tsc2007 *ts)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
1098c2ecf20Sopenharmony_ci	struct tsc2007_iio *iio;
1108c2ecf20Sopenharmony_ci	int error;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&ts->client->dev, sizeof(*iio));
1138c2ecf20Sopenharmony_ci	if (!indio_dev) {
1148c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "iio_device_alloc failed\n");
1158c2ecf20Sopenharmony_ci		return -ENOMEM;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	iio = iio_priv(indio_dev);
1198c2ecf20Sopenharmony_ci	iio->ts = ts;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	indio_dev->name = "tsc2007";
1228c2ecf20Sopenharmony_ci	indio_dev->info = &tsc2007_iio_info;
1238c2ecf20Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
1248c2ecf20Sopenharmony_ci	indio_dev->channels = tsc2007_iio_channel;
1258c2ecf20Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(tsc2007_iio_channel);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	error = devm_iio_device_register(&ts->client->dev, indio_dev);
1288c2ecf20Sopenharmony_ci	if (error) {
1298c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
1308c2ecf20Sopenharmony_ci			"iio_device_register() failed: %d\n", error);
1318c2ecf20Sopenharmony_ci		return error;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
136