18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * srf08.c - Support for Devantech SRFxx ultrasonic ranger
48c2ecf20Sopenharmony_ci *           with i2c interface
58c2ecf20Sopenharmony_ci * actually supported are srf02, srf08, srf10
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2016, 2017 Andreas Klinger <ak@it-klinger.de>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * For details about the device see:
108c2ecf20Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf08tech.html
118c2ecf20Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf10tech.htm
128c2ecf20Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf02tech.htm
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/i2c.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/bitops.h>
208c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
218c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h>
228c2ecf20Sopenharmony_ci#include <linux/iio/buffer.h>
238c2ecf20Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
248c2ecf20Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* registers of SRF08 device */
278c2ecf20Sopenharmony_ci#define SRF08_WRITE_COMMAND	0x00	/* Command Register */
288c2ecf20Sopenharmony_ci#define SRF08_WRITE_MAX_GAIN	0x01	/* Max Gain Register: 0 .. 31 */
298c2ecf20Sopenharmony_ci#define SRF08_WRITE_RANGE	0x02	/* Range Register: 0 .. 255 */
308c2ecf20Sopenharmony_ci#define SRF08_READ_SW_REVISION	0x00	/* Software Revision */
318c2ecf20Sopenharmony_ci#define SRF08_READ_LIGHT	0x01	/* Light Sensor during last echo */
328c2ecf20Sopenharmony_ci#define SRF08_READ_ECHO_1_HIGH	0x02	/* Range of first echo received */
338c2ecf20Sopenharmony_ci#define SRF08_READ_ECHO_1_LOW	0x03	/* Range of first echo received */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define SRF08_CMD_RANGING_CM	0x51	/* Ranging Mode - Result in cm */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cienum srf08_sensor_type {
388c2ecf20Sopenharmony_ci	SRF02,
398c2ecf20Sopenharmony_ci	SRF08,
408c2ecf20Sopenharmony_ci	SRF10,
418c2ecf20Sopenharmony_ci	SRF_MAX_TYPE
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct srf08_chip_info {
458c2ecf20Sopenharmony_ci	const int		*sensitivity_avail;
468c2ecf20Sopenharmony_ci	int			num_sensitivity_avail;
478c2ecf20Sopenharmony_ci	int			sensitivity_default;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* default value of Range in mm */
508c2ecf20Sopenharmony_ci	int			range_default;
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistruct srf08_data {
548c2ecf20Sopenharmony_ci	struct i2c_client	*client;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * Gain in the datasheet is called sensitivity here to distinct it
588c2ecf20Sopenharmony_ci	 * from the gain used with amplifiers of adc's
598c2ecf20Sopenharmony_ci	 */
608c2ecf20Sopenharmony_ci	int			sensitivity;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* max. Range in mm */
638c2ecf20Sopenharmony_ci	int			range_mm;
648c2ecf20Sopenharmony_ci	struct mutex		lock;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/* Ensure timestamp is naturally aligned */
678c2ecf20Sopenharmony_ci	struct {
688c2ecf20Sopenharmony_ci		s16 chan;
698c2ecf20Sopenharmony_ci		s64 timestamp __aligned(8);
708c2ecf20Sopenharmony_ci	} scan;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* Sensor-Type */
738c2ecf20Sopenharmony_ci	enum srf08_sensor_type	sensor_type;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* Chip-specific information */
768c2ecf20Sopenharmony_ci	const struct srf08_chip_info	*chip_info;
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * in the documentation one can read about the "Gain" of the device
818c2ecf20Sopenharmony_ci * which is used here for amplifying the signal and filtering out unwanted
828c2ecf20Sopenharmony_ci * ones.
838c2ecf20Sopenharmony_ci * But with ADC's this term is already used differently and that's why it
848c2ecf20Sopenharmony_ci * is called "Sensitivity" here.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic const struct srf08_chip_info srf02_chip_info = {
878c2ecf20Sopenharmony_ci	.sensitivity_avail	= NULL,
888c2ecf20Sopenharmony_ci	.num_sensitivity_avail	= 0,
898c2ecf20Sopenharmony_ci	.sensitivity_default	= 0,
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	.range_default		= 0,
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic const int srf08_sensitivity_avail[] = {
958c2ecf20Sopenharmony_ci	 94,  97, 100, 103, 107, 110, 114, 118,
968c2ecf20Sopenharmony_ci	123, 128, 133, 139, 145, 152, 159, 168,
978c2ecf20Sopenharmony_ci	177, 187, 199, 212, 227, 245, 265, 288,
988c2ecf20Sopenharmony_ci	317, 352, 395, 450, 524, 626, 777, 1025
998c2ecf20Sopenharmony_ci	};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic const struct srf08_chip_info srf08_chip_info = {
1028c2ecf20Sopenharmony_ci	.sensitivity_avail	= srf08_sensitivity_avail,
1038c2ecf20Sopenharmony_ci	.num_sensitivity_avail	= ARRAY_SIZE(srf08_sensitivity_avail),
1048c2ecf20Sopenharmony_ci	.sensitivity_default	= 1025,
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	.range_default		= 6020,
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic const int srf10_sensitivity_avail[] = {
1108c2ecf20Sopenharmony_ci	 40,  40,  50,  60,  70,  80, 100, 120,
1118c2ecf20Sopenharmony_ci	140, 200, 250, 300, 350, 400, 500, 600,
1128c2ecf20Sopenharmony_ci	700,
1138c2ecf20Sopenharmony_ci	};
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic const struct srf08_chip_info srf10_chip_info = {
1168c2ecf20Sopenharmony_ci	.sensitivity_avail	= srf10_sensitivity_avail,
1178c2ecf20Sopenharmony_ci	.num_sensitivity_avail	= ARRAY_SIZE(srf10_sensitivity_avail),
1188c2ecf20Sopenharmony_ci	.sensitivity_default	= 700,
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	.range_default		= 6020,
1218c2ecf20Sopenharmony_ci};
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int srf08_read_ranging(struct srf08_data *data)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
1268c2ecf20Sopenharmony_ci	int ret, i;
1278c2ecf20Sopenharmony_ci	int waittime;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(data->client,
1328c2ecf20Sopenharmony_ci			SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
1338c2ecf20Sopenharmony_ci	if (ret < 0) {
1348c2ecf20Sopenharmony_ci		dev_err(&client->dev, "write command - err: %d\n", ret);
1358c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
1368c2ecf20Sopenharmony_ci		return ret;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/*
1408c2ecf20Sopenharmony_ci	 * we read here until a correct version number shows up as
1418c2ecf20Sopenharmony_ci	 * suggested by the documentation
1428c2ecf20Sopenharmony_ci	 *
1438c2ecf20Sopenharmony_ci	 * with an ultrasonic speed of 343 m/s and a roundtrip of it
1448c2ecf20Sopenharmony_ci	 * sleep the expected duration and try to read from the device
1458c2ecf20Sopenharmony_ci	 * if nothing useful is read try it in a shorter grid
1468c2ecf20Sopenharmony_ci	 *
1478c2ecf20Sopenharmony_ci	 * polling for not more than 20 ms should be enough
1488c2ecf20Sopenharmony_ci	 */
1498c2ecf20Sopenharmony_ci	waittime = 1 + data->range_mm / 172;
1508c2ecf20Sopenharmony_ci	msleep(waittime);
1518c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
1528c2ecf20Sopenharmony_ci		ret = i2c_smbus_read_byte_data(data->client,
1538c2ecf20Sopenharmony_ci						SRF08_READ_SW_REVISION);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		/* check if a valid version number is read */
1568c2ecf20Sopenharmony_ci		if (ret < 255 && ret > 0)
1578c2ecf20Sopenharmony_ci			break;
1588c2ecf20Sopenharmony_ci		msleep(5);
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (ret >= 255 || ret <= 0) {
1628c2ecf20Sopenharmony_ci		dev_err(&client->dev, "device not ready\n");
1638c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
1648c2ecf20Sopenharmony_ci		return -EIO;
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_word_swapped(data->client,
1688c2ecf20Sopenharmony_ci						SRF08_READ_ECHO_1_HIGH);
1698c2ecf20Sopenharmony_ci	if (ret < 0) {
1708c2ecf20Sopenharmony_ci		dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
1718c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
1728c2ecf20Sopenharmony_ci		return ret;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return ret;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic irqreturn_t srf08_trigger_handler(int irq, void *p)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct iio_poll_func *pf = p;
1838c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
1848c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
1858c2ecf20Sopenharmony_ci	s16 sensor_data;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	sensor_data = srf08_read_ranging(data);
1888c2ecf20Sopenharmony_ci	if (sensor_data < 0)
1898c2ecf20Sopenharmony_ci		goto err;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	data->scan.chan = sensor_data;
1948c2ecf20Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev,
1958c2ecf20Sopenharmony_ci					   &data->scan, pf->timestamp);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
1988c2ecf20Sopenharmony_cierr:
1998c2ecf20Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
2008c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int srf08_read_raw(struct iio_dev *indio_dev,
2048c2ecf20Sopenharmony_ci			    struct iio_chan_spec const *channel, int *val,
2058c2ecf20Sopenharmony_ci			    int *val2, long mask)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
2088c2ecf20Sopenharmony_ci	int ret;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (channel->type != IIO_DISTANCE)
2118c2ecf20Sopenharmony_ci		return -EINVAL;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	switch (mask) {
2148c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
2158c2ecf20Sopenharmony_ci		ret = srf08_read_ranging(data);
2168c2ecf20Sopenharmony_ci		if (ret < 0)
2178c2ecf20Sopenharmony_ci			return ret;
2188c2ecf20Sopenharmony_ci		*val = ret;
2198c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
2208c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
2218c2ecf20Sopenharmony_ci		/* 1 LSB is 1 cm */
2228c2ecf20Sopenharmony_ci		*val = 0;
2238c2ecf20Sopenharmony_ci		*val2 = 10000;
2248c2ecf20Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
2258c2ecf20Sopenharmony_ci	default:
2268c2ecf20Sopenharmony_ci		return -EINVAL;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic ssize_t srf08_show_range_mm_available(struct device *dev,
2318c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	return sprintf(buf, "[0.043 0.043 11.008]\n");
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO,
2378c2ecf20Sopenharmony_ci				srf08_show_range_mm_available, NULL, 0);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic ssize_t srf08_show_range_mm(struct device *dev,
2408c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
2438c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return sprintf(buf, "%d.%03d\n", data->range_mm / 1000,
2468c2ecf20Sopenharmony_ci						data->range_mm % 1000);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/*
2508c2ecf20Sopenharmony_ci * set the range of the sensor to an even multiple of 43 mm
2518c2ecf20Sopenharmony_ci * which corresponds to 1 LSB in the register
2528c2ecf20Sopenharmony_ci *
2538c2ecf20Sopenharmony_ci * register value    corresponding range
2548c2ecf20Sopenharmony_ci *         0x00             43 mm
2558c2ecf20Sopenharmony_ci *         0x01             86 mm
2568c2ecf20Sopenharmony_ci *         0x02            129 mm
2578c2ecf20Sopenharmony_ci *         ...
2588c2ecf20Sopenharmony_ci *         0xFF          11008 mm
2598c2ecf20Sopenharmony_ci */
2608c2ecf20Sopenharmony_cistatic ssize_t srf08_write_range_mm(struct srf08_data *data, unsigned int val)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	int ret;
2638c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
2648c2ecf20Sopenharmony_ci	unsigned int mod;
2658c2ecf20Sopenharmony_ci	u8 regval;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	ret = val / 43 - 1;
2688c2ecf20Sopenharmony_ci	mod = val % 43;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (mod || (ret < 0) || (ret > 255))
2718c2ecf20Sopenharmony_ci		return -EINVAL;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	regval = ret;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_RANGE, regval);
2788c2ecf20Sopenharmony_ci	if (ret < 0) {
2798c2ecf20Sopenharmony_ci		dev_err(&client->dev, "write_range - err: %d\n", ret);
2808c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
2818c2ecf20Sopenharmony_ci		return ret;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	data->range_mm = val;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic ssize_t srf08_store_range_mm(struct device *dev,
2928c2ecf20Sopenharmony_ci					struct device_attribute *attr,
2938c2ecf20Sopenharmony_ci					const char *buf, size_t len)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
2968c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
2978c2ecf20Sopenharmony_ci	int ret;
2988c2ecf20Sopenharmony_ci	int integer, fract;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
3018c2ecf20Sopenharmony_ci	if (ret)
3028c2ecf20Sopenharmony_ci		return ret;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	ret = srf08_write_range_mm(data, integer * 1000 + fract);
3058c2ecf20Sopenharmony_ci	if (ret < 0)
3068c2ecf20Sopenharmony_ci		return ret;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return len;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_max_range, S_IRUGO | S_IWUSR,
3128c2ecf20Sopenharmony_ci			srf08_show_range_mm, srf08_store_range_mm, 0);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic ssize_t srf08_show_sensitivity_available(struct device *dev,
3158c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	int i, len = 0;
3188c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
3198c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
3228c2ecf20Sopenharmony_ci		if (data->chip_info->sensitivity_avail[i])
3238c2ecf20Sopenharmony_ci			len += sprintf(buf + len, "%d ",
3248c2ecf20Sopenharmony_ci				data->chip_info->sensitivity_avail[i]);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	len += sprintf(buf + len, "\n");
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return len;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_sensitivity_available, S_IRUGO,
3328c2ecf20Sopenharmony_ci				srf08_show_sensitivity_available, NULL, 0);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic ssize_t srf08_show_sensitivity(struct device *dev,
3358c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
3388c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
3398c2ecf20Sopenharmony_ci	int len;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	len = sprintf(buf, "%d\n", data->sensitivity);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return len;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic ssize_t srf08_write_sensitivity(struct srf08_data *data,
3478c2ecf20Sopenharmony_ci							unsigned int val)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
3508c2ecf20Sopenharmony_ci	int ret, i;
3518c2ecf20Sopenharmony_ci	u8 regval;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (!val)
3548c2ecf20Sopenharmony_ci		return -EINVAL;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
3578c2ecf20Sopenharmony_ci		if (val && (val == data->chip_info->sensitivity_avail[i])) {
3588c2ecf20Sopenharmony_ci			regval = i;
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (i >= data->chip_info->num_sensitivity_avail)
3638c2ecf20Sopenharmony_ci		return -EINVAL;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_MAX_GAIN, regval);
3688c2ecf20Sopenharmony_ci	if (ret < 0) {
3698c2ecf20Sopenharmony_ci		dev_err(&client->dev, "write_sensitivity - err: %d\n", ret);
3708c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
3718c2ecf20Sopenharmony_ci		return ret;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	data->sensitivity = val;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return 0;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic ssize_t srf08_store_sensitivity(struct device *dev,
3828c2ecf20Sopenharmony_ci						struct device_attribute *attr,
3838c2ecf20Sopenharmony_ci						const char *buf, size_t len)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
3868c2ecf20Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
3878c2ecf20Sopenharmony_ci	int ret;
3888c2ecf20Sopenharmony_ci	unsigned int val;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	ret = kstrtouint(buf, 10, &val);
3918c2ecf20Sopenharmony_ci	if (ret)
3928c2ecf20Sopenharmony_ci		return ret;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	ret = srf08_write_sensitivity(data, val);
3958c2ecf20Sopenharmony_ci	if (ret < 0)
3968c2ecf20Sopenharmony_ci		return ret;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return len;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
4028c2ecf20Sopenharmony_ci			srf08_show_sensitivity, srf08_store_sensitivity, 0);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic struct attribute *srf08_attributes[] = {
4058c2ecf20Sopenharmony_ci	&iio_dev_attr_sensor_max_range.dev_attr.attr,
4068c2ecf20Sopenharmony_ci	&iio_dev_attr_sensor_max_range_available.dev_attr.attr,
4078c2ecf20Sopenharmony_ci	&iio_dev_attr_sensor_sensitivity.dev_attr.attr,
4088c2ecf20Sopenharmony_ci	&iio_dev_attr_sensor_sensitivity_available.dev_attr.attr,
4098c2ecf20Sopenharmony_ci	NULL,
4108c2ecf20Sopenharmony_ci};
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic const struct attribute_group srf08_attribute_group = {
4138c2ecf20Sopenharmony_ci	.attrs = srf08_attributes,
4148c2ecf20Sopenharmony_ci};
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic const struct iio_chan_spec srf08_channels[] = {
4178c2ecf20Sopenharmony_ci	{
4188c2ecf20Sopenharmony_ci		.type = IIO_DISTANCE,
4198c2ecf20Sopenharmony_ci		.info_mask_separate =
4208c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_RAW) |
4218c2ecf20Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE),
4228c2ecf20Sopenharmony_ci		.scan_index = 0,
4238c2ecf20Sopenharmony_ci		.scan_type = {
4248c2ecf20Sopenharmony_ci			.sign = 's',
4258c2ecf20Sopenharmony_ci			.realbits = 16,
4268c2ecf20Sopenharmony_ci			.storagebits = 16,
4278c2ecf20Sopenharmony_ci			.endianness = IIO_CPU,
4288c2ecf20Sopenharmony_ci		},
4298c2ecf20Sopenharmony_ci	},
4308c2ecf20Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(1),
4318c2ecf20Sopenharmony_ci};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic const struct iio_info srf08_info = {
4348c2ecf20Sopenharmony_ci	.read_raw = srf08_read_raw,
4358c2ecf20Sopenharmony_ci	.attrs = &srf08_attribute_group,
4368c2ecf20Sopenharmony_ci};
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/*
4398c2ecf20Sopenharmony_ci * srf02 don't have an adjustable range or sensitivity,
4408c2ecf20Sopenharmony_ci * so we don't need attributes at all
4418c2ecf20Sopenharmony_ci */
4428c2ecf20Sopenharmony_cistatic const struct iio_info srf02_info = {
4438c2ecf20Sopenharmony_ci	.read_raw = srf08_read_raw,
4448c2ecf20Sopenharmony_ci};
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic int srf08_probe(struct i2c_client *client,
4478c2ecf20Sopenharmony_ci					 const struct i2c_device_id *id)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
4508c2ecf20Sopenharmony_ci	struct srf08_data *data;
4518c2ecf20Sopenharmony_ci	int ret;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
4548c2ecf20Sopenharmony_ci					I2C_FUNC_SMBUS_READ_BYTE_DATA |
4558c2ecf20Sopenharmony_ci					I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
4568c2ecf20Sopenharmony_ci					I2C_FUNC_SMBUS_READ_WORD_DATA))
4578c2ecf20Sopenharmony_ci		return -ENODEV;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
4608c2ecf20Sopenharmony_ci	if (!indio_dev)
4618c2ecf20Sopenharmony_ci		return -ENOMEM;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	data = iio_priv(indio_dev);
4648c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
4658c2ecf20Sopenharmony_ci	data->client = client;
4668c2ecf20Sopenharmony_ci	data->sensor_type = (enum srf08_sensor_type)id->driver_data;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	switch (data->sensor_type) {
4698c2ecf20Sopenharmony_ci	case SRF02:
4708c2ecf20Sopenharmony_ci		data->chip_info = &srf02_chip_info;
4718c2ecf20Sopenharmony_ci		indio_dev->info = &srf02_info;
4728c2ecf20Sopenharmony_ci		break;
4738c2ecf20Sopenharmony_ci	case SRF08:
4748c2ecf20Sopenharmony_ci		data->chip_info = &srf08_chip_info;
4758c2ecf20Sopenharmony_ci		indio_dev->info = &srf08_info;
4768c2ecf20Sopenharmony_ci		break;
4778c2ecf20Sopenharmony_ci	case SRF10:
4788c2ecf20Sopenharmony_ci		data->chip_info = &srf10_chip_info;
4798c2ecf20Sopenharmony_ci		indio_dev->info = &srf08_info;
4808c2ecf20Sopenharmony_ci		break;
4818c2ecf20Sopenharmony_ci	default:
4828c2ecf20Sopenharmony_ci		return -EINVAL;
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	indio_dev->name = id->name;
4868c2ecf20Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
4878c2ecf20Sopenharmony_ci	indio_dev->channels = srf08_channels;
4888c2ecf20Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	mutex_init(&data->lock);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
4938c2ecf20Sopenharmony_ci			iio_pollfunc_store_time, srf08_trigger_handler, NULL);
4948c2ecf20Sopenharmony_ci	if (ret < 0) {
4958c2ecf20Sopenharmony_ci		dev_err(&client->dev, "setup of iio triggered buffer failed\n");
4968c2ecf20Sopenharmony_ci		return ret;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (data->chip_info->range_default) {
5008c2ecf20Sopenharmony_ci		/*
5018c2ecf20Sopenharmony_ci		 * set default range of device in mm here
5028c2ecf20Sopenharmony_ci		 * these register values cannot be read from the hardware
5038c2ecf20Sopenharmony_ci		 * therefore set driver specific default values
5048c2ecf20Sopenharmony_ci		 *
5058c2ecf20Sopenharmony_ci		 * srf02 don't have a default value so it'll be omitted
5068c2ecf20Sopenharmony_ci		 */
5078c2ecf20Sopenharmony_ci		ret = srf08_write_range_mm(data,
5088c2ecf20Sopenharmony_ci					data->chip_info->range_default);
5098c2ecf20Sopenharmony_ci		if (ret < 0)
5108c2ecf20Sopenharmony_ci			return ret;
5118c2ecf20Sopenharmony_ci	}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	if (data->chip_info->sensitivity_default) {
5148c2ecf20Sopenharmony_ci		/*
5158c2ecf20Sopenharmony_ci		 * set default sensitivity of device here
5168c2ecf20Sopenharmony_ci		 * these register values cannot be read from the hardware
5178c2ecf20Sopenharmony_ci		 * therefore set driver specific default values
5188c2ecf20Sopenharmony_ci		 *
5198c2ecf20Sopenharmony_ci		 * srf02 don't have a default value so it'll be omitted
5208c2ecf20Sopenharmony_ci		 */
5218c2ecf20Sopenharmony_ci		ret = srf08_write_sensitivity(data,
5228c2ecf20Sopenharmony_ci				data->chip_info->sensitivity_default);
5238c2ecf20Sopenharmony_ci		if (ret < 0)
5248c2ecf20Sopenharmony_ci			return ret;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
5288c2ecf20Sopenharmony_ci}
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_cistatic const struct of_device_id of_srf08_match[] = {
5318c2ecf20Sopenharmony_ci	{ .compatible = "devantech,srf02", (void *)SRF02},
5328c2ecf20Sopenharmony_ci	{ .compatible = "devantech,srf08", (void *)SRF08},
5338c2ecf20Sopenharmony_ci	{ .compatible = "devantech,srf10", (void *)SRF10},
5348c2ecf20Sopenharmony_ci	{},
5358c2ecf20Sopenharmony_ci};
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_srf08_match);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic const struct i2c_device_id srf08_id[] = {
5408c2ecf20Sopenharmony_ci	{ "srf02", SRF02 },
5418c2ecf20Sopenharmony_ci	{ "srf08", SRF08 },
5428c2ecf20Sopenharmony_ci	{ "srf10", SRF10 },
5438c2ecf20Sopenharmony_ci	{ }
5448c2ecf20Sopenharmony_ci};
5458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, srf08_id);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cistatic struct i2c_driver srf08_driver = {
5488c2ecf20Sopenharmony_ci	.driver = {
5498c2ecf20Sopenharmony_ci		.name	= "srf08",
5508c2ecf20Sopenharmony_ci		.of_match_table	= of_srf08_match,
5518c2ecf20Sopenharmony_ci	},
5528c2ecf20Sopenharmony_ci	.probe = srf08_probe,
5538c2ecf20Sopenharmony_ci	.id_table = srf08_id,
5548c2ecf20Sopenharmony_ci};
5558c2ecf20Sopenharmony_cimodule_i2c_driver(srf08_driver);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
5588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Devantech SRF02/SRF08/SRF10 i2c ultrasonic ranger driver");
5598c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
560