162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * srf08.c - Support for Devantech SRFxx ultrasonic ranger
462306a36Sopenharmony_ci *           with i2c interface
562306a36Sopenharmony_ci * actually supported are srf02, srf08, srf10
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2016, 2017 Andreas Klinger <ak@it-klinger.de>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * For details about the device see:
1062306a36Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf08tech.html
1162306a36Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf10tech.htm
1262306a36Sopenharmony_ci * https://www.robot-electronics.co.uk/htm/srf02tech.htm
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/err.h>
1662306a36Sopenharmony_ci#include <linux/i2c.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/bitops.h>
2062306a36Sopenharmony_ci#include <linux/iio/iio.h>
2162306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2262306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2362306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
2462306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* registers of SRF08 device */
2762306a36Sopenharmony_ci#define SRF08_WRITE_COMMAND	0x00	/* Command Register */
2862306a36Sopenharmony_ci#define SRF08_WRITE_MAX_GAIN	0x01	/* Max Gain Register: 0 .. 31 */
2962306a36Sopenharmony_ci#define SRF08_WRITE_RANGE	0x02	/* Range Register: 0 .. 255 */
3062306a36Sopenharmony_ci#define SRF08_READ_SW_REVISION	0x00	/* Software Revision */
3162306a36Sopenharmony_ci#define SRF08_READ_LIGHT	0x01	/* Light Sensor during last echo */
3262306a36Sopenharmony_ci#define SRF08_READ_ECHO_1_HIGH	0x02	/* Range of first echo received */
3362306a36Sopenharmony_ci#define SRF08_READ_ECHO_1_LOW	0x03	/* Range of first echo received */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define SRF08_CMD_RANGING_CM	0x51	/* Ranging Mode - Result in cm */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cienum srf08_sensor_type {
3862306a36Sopenharmony_ci	SRF02,
3962306a36Sopenharmony_ci	SRF08,
4062306a36Sopenharmony_ci	SRF10,
4162306a36Sopenharmony_ci	SRF_MAX_TYPE
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct srf08_chip_info {
4562306a36Sopenharmony_ci	const int		*sensitivity_avail;
4662306a36Sopenharmony_ci	int			num_sensitivity_avail;
4762306a36Sopenharmony_ci	int			sensitivity_default;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* default value of Range in mm */
5062306a36Sopenharmony_ci	int			range_default;
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct srf08_data {
5462306a36Sopenharmony_ci	struct i2c_client	*client;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * Gain in the datasheet is called sensitivity here to distinct it
5862306a36Sopenharmony_ci	 * from the gain used with amplifiers of adc's
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	int			sensitivity;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* max. Range in mm */
6362306a36Sopenharmony_ci	int			range_mm;
6462306a36Sopenharmony_ci	struct mutex		lock;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Ensure timestamp is naturally aligned */
6762306a36Sopenharmony_ci	struct {
6862306a36Sopenharmony_ci		s16 chan;
6962306a36Sopenharmony_ci		s64 timestamp __aligned(8);
7062306a36Sopenharmony_ci	} scan;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* Sensor-Type */
7362306a36Sopenharmony_ci	enum srf08_sensor_type	sensor_type;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Chip-specific information */
7662306a36Sopenharmony_ci	const struct srf08_chip_info	*chip_info;
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * in the documentation one can read about the "Gain" of the device
8162306a36Sopenharmony_ci * which is used here for amplifying the signal and filtering out unwanted
8262306a36Sopenharmony_ci * ones.
8362306a36Sopenharmony_ci * But with ADC's this term is already used differently and that's why it
8462306a36Sopenharmony_ci * is called "Sensitivity" here.
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic const struct srf08_chip_info srf02_chip_info = {
8762306a36Sopenharmony_ci	.sensitivity_avail	= NULL,
8862306a36Sopenharmony_ci	.num_sensitivity_avail	= 0,
8962306a36Sopenharmony_ci	.sensitivity_default	= 0,
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	.range_default		= 0,
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic const int srf08_sensitivity_avail[] = {
9562306a36Sopenharmony_ci	 94,  97, 100, 103, 107, 110, 114, 118,
9662306a36Sopenharmony_ci	123, 128, 133, 139, 145, 152, 159, 168,
9762306a36Sopenharmony_ci	177, 187, 199, 212, 227, 245, 265, 288,
9862306a36Sopenharmony_ci	317, 352, 395, 450, 524, 626, 777, 1025
9962306a36Sopenharmony_ci	};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic const struct srf08_chip_info srf08_chip_info = {
10262306a36Sopenharmony_ci	.sensitivity_avail	= srf08_sensitivity_avail,
10362306a36Sopenharmony_ci	.num_sensitivity_avail	= ARRAY_SIZE(srf08_sensitivity_avail),
10462306a36Sopenharmony_ci	.sensitivity_default	= 1025,
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	.range_default		= 6020,
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic const int srf10_sensitivity_avail[] = {
11062306a36Sopenharmony_ci	 40,  40,  50,  60,  70,  80, 100, 120,
11162306a36Sopenharmony_ci	140, 200, 250, 300, 350, 400, 500, 600,
11262306a36Sopenharmony_ci	700,
11362306a36Sopenharmony_ci	};
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic const struct srf08_chip_info srf10_chip_info = {
11662306a36Sopenharmony_ci	.sensitivity_avail	= srf10_sensitivity_avail,
11762306a36Sopenharmony_ci	.num_sensitivity_avail	= ARRAY_SIZE(srf10_sensitivity_avail),
11862306a36Sopenharmony_ci	.sensitivity_default	= 700,
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	.range_default		= 6020,
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int srf08_read_ranging(struct srf08_data *data)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct i2c_client *client = data->client;
12662306a36Sopenharmony_ci	int ret, i;
12762306a36Sopenharmony_ci	int waittime;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	mutex_lock(&data->lock);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(data->client,
13262306a36Sopenharmony_ci			SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
13362306a36Sopenharmony_ci	if (ret < 0) {
13462306a36Sopenharmony_ci		dev_err(&client->dev, "write command - err: %d\n", ret);
13562306a36Sopenharmony_ci		mutex_unlock(&data->lock);
13662306a36Sopenharmony_ci		return ret;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/*
14062306a36Sopenharmony_ci	 * we read here until a correct version number shows up as
14162306a36Sopenharmony_ci	 * suggested by the documentation
14262306a36Sopenharmony_ci	 *
14362306a36Sopenharmony_ci	 * with an ultrasonic speed of 343 m/s and a roundtrip of it
14462306a36Sopenharmony_ci	 * sleep the expected duration and try to read from the device
14562306a36Sopenharmony_ci	 * if nothing useful is read try it in a shorter grid
14662306a36Sopenharmony_ci	 *
14762306a36Sopenharmony_ci	 * polling for not more than 20 ms should be enough
14862306a36Sopenharmony_ci	 */
14962306a36Sopenharmony_ci	waittime = 1 + data->range_mm / 172;
15062306a36Sopenharmony_ci	msleep(waittime);
15162306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
15262306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(data->client,
15362306a36Sopenharmony_ci						SRF08_READ_SW_REVISION);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		/* check if a valid version number is read */
15662306a36Sopenharmony_ci		if (ret < 255 && ret > 0)
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		msleep(5);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (ret >= 255 || ret <= 0) {
16262306a36Sopenharmony_ci		dev_err(&client->dev, "device not ready\n");
16362306a36Sopenharmony_ci		mutex_unlock(&data->lock);
16462306a36Sopenharmony_ci		return -EIO;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	ret = i2c_smbus_read_word_swapped(data->client,
16862306a36Sopenharmony_ci						SRF08_READ_ECHO_1_HIGH);
16962306a36Sopenharmony_ci	if (ret < 0) {
17062306a36Sopenharmony_ci		dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
17162306a36Sopenharmony_ci		mutex_unlock(&data->lock);
17262306a36Sopenharmony_ci		return ret;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	mutex_unlock(&data->lock);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	return ret;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic irqreturn_t srf08_trigger_handler(int irq, void *p)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
18362306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
18462306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
18562306a36Sopenharmony_ci	s16 sensor_data;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	sensor_data = srf08_read_ranging(data);
18862306a36Sopenharmony_ci	if (sensor_data < 0)
18962306a36Sopenharmony_ci		goto err;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mutex_lock(&data->lock);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	data->scan.chan = sensor_data;
19462306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev,
19562306a36Sopenharmony_ci					   &data->scan, pf->timestamp);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	mutex_unlock(&data->lock);
19862306a36Sopenharmony_cierr:
19962306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
20062306a36Sopenharmony_ci	return IRQ_HANDLED;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int srf08_read_raw(struct iio_dev *indio_dev,
20462306a36Sopenharmony_ci			    struct iio_chan_spec const *channel, int *val,
20562306a36Sopenharmony_ci			    int *val2, long mask)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
20862306a36Sopenharmony_ci	int ret;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (channel->type != IIO_DISTANCE)
21162306a36Sopenharmony_ci		return -EINVAL;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	switch (mask) {
21462306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
21562306a36Sopenharmony_ci		ret = srf08_read_ranging(data);
21662306a36Sopenharmony_ci		if (ret < 0)
21762306a36Sopenharmony_ci			return ret;
21862306a36Sopenharmony_ci		*val = ret;
21962306a36Sopenharmony_ci		return IIO_VAL_INT;
22062306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
22162306a36Sopenharmony_ci		/* 1 LSB is 1 cm */
22262306a36Sopenharmony_ci		*val = 0;
22362306a36Sopenharmony_ci		*val2 = 10000;
22462306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
22562306a36Sopenharmony_ci	default:
22662306a36Sopenharmony_ci		return -EINVAL;
22762306a36Sopenharmony_ci	}
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic ssize_t srf08_show_range_mm_available(struct device *dev,
23162306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	return sprintf(buf, "[0.043 0.043 11.008]\n");
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO,
23762306a36Sopenharmony_ci				srf08_show_range_mm_available, NULL, 0);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic ssize_t srf08_show_range_mm(struct device *dev,
24062306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
24362306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return sprintf(buf, "%d.%03d\n", data->range_mm / 1000,
24662306a36Sopenharmony_ci						data->range_mm % 1000);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci/*
25062306a36Sopenharmony_ci * set the range of the sensor to an even multiple of 43 mm
25162306a36Sopenharmony_ci * which corresponds to 1 LSB in the register
25262306a36Sopenharmony_ci *
25362306a36Sopenharmony_ci * register value    corresponding range
25462306a36Sopenharmony_ci *         0x00             43 mm
25562306a36Sopenharmony_ci *         0x01             86 mm
25662306a36Sopenharmony_ci *         0x02            129 mm
25762306a36Sopenharmony_ci *         ...
25862306a36Sopenharmony_ci *         0xFF          11008 mm
25962306a36Sopenharmony_ci */
26062306a36Sopenharmony_cistatic ssize_t srf08_write_range_mm(struct srf08_data *data, unsigned int val)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	int ret;
26362306a36Sopenharmony_ci	struct i2c_client *client = data->client;
26462306a36Sopenharmony_ci	unsigned int mod;
26562306a36Sopenharmony_ci	u8 regval;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	ret = val / 43 - 1;
26862306a36Sopenharmony_ci	mod = val % 43;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (mod || (ret < 0) || (ret > 255))
27162306a36Sopenharmony_ci		return -EINVAL;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	regval = ret;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	mutex_lock(&data->lock);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_RANGE, regval);
27862306a36Sopenharmony_ci	if (ret < 0) {
27962306a36Sopenharmony_ci		dev_err(&client->dev, "write_range - err: %d\n", ret);
28062306a36Sopenharmony_ci		mutex_unlock(&data->lock);
28162306a36Sopenharmony_ci		return ret;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	data->range_mm = val;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	mutex_unlock(&data->lock);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic ssize_t srf08_store_range_mm(struct device *dev,
29262306a36Sopenharmony_ci					struct device_attribute *attr,
29362306a36Sopenharmony_ci					const char *buf, size_t len)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
29662306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
29762306a36Sopenharmony_ci	int ret;
29862306a36Sopenharmony_ci	int integer, fract;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
30162306a36Sopenharmony_ci	if (ret)
30262306a36Sopenharmony_ci		return ret;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	ret = srf08_write_range_mm(data, integer * 1000 + fract);
30562306a36Sopenharmony_ci	if (ret < 0)
30662306a36Sopenharmony_ci		return ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return len;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_max_range, S_IRUGO | S_IWUSR,
31262306a36Sopenharmony_ci			srf08_show_range_mm, srf08_store_range_mm, 0);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic ssize_t srf08_show_sensitivity_available(struct device *dev,
31562306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	int i, len = 0;
31862306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
31962306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
32262306a36Sopenharmony_ci		if (data->chip_info->sensitivity_avail[i])
32362306a36Sopenharmony_ci			len += sprintf(buf + len, "%d ",
32462306a36Sopenharmony_ci				data->chip_info->sensitivity_avail[i]);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	len += sprintf(buf + len, "\n");
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return len;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_sensitivity_available, S_IRUGO,
33262306a36Sopenharmony_ci				srf08_show_sensitivity_available, NULL, 0);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic ssize_t srf08_show_sensitivity(struct device *dev,
33562306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
33862306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
33962306a36Sopenharmony_ci	int len;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	len = sprintf(buf, "%d\n", data->sensitivity);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return len;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic ssize_t srf08_write_sensitivity(struct srf08_data *data,
34762306a36Sopenharmony_ci							unsigned int val)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct i2c_client *client = data->client;
35062306a36Sopenharmony_ci	int ret, i;
35162306a36Sopenharmony_ci	u8 regval;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (!val)
35462306a36Sopenharmony_ci		return -EINVAL;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	for (i = 0; i < data->chip_info->num_sensitivity_avail; i++)
35762306a36Sopenharmony_ci		if (val == data->chip_info->sensitivity_avail[i]) {
35862306a36Sopenharmony_ci			regval = i;
35962306a36Sopenharmony_ci			break;
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (i >= data->chip_info->num_sensitivity_avail)
36362306a36Sopenharmony_ci		return -EINVAL;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	mutex_lock(&data->lock);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_MAX_GAIN, regval);
36862306a36Sopenharmony_ci	if (ret < 0) {
36962306a36Sopenharmony_ci		dev_err(&client->dev, "write_sensitivity - err: %d\n", ret);
37062306a36Sopenharmony_ci		mutex_unlock(&data->lock);
37162306a36Sopenharmony_ci		return ret;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	data->sensitivity = val;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	mutex_unlock(&data->lock);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return 0;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic ssize_t srf08_store_sensitivity(struct device *dev,
38262306a36Sopenharmony_ci						struct device_attribute *attr,
38362306a36Sopenharmony_ci						const char *buf, size_t len)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
38662306a36Sopenharmony_ci	struct srf08_data *data = iio_priv(indio_dev);
38762306a36Sopenharmony_ci	int ret;
38862306a36Sopenharmony_ci	unsigned int val;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = kstrtouint(buf, 10, &val);
39162306a36Sopenharmony_ci	if (ret)
39262306a36Sopenharmony_ci		return ret;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	ret = srf08_write_sensitivity(data, val);
39562306a36Sopenharmony_ci	if (ret < 0)
39662306a36Sopenharmony_ci		return ret;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return len;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
40262306a36Sopenharmony_ci			srf08_show_sensitivity, srf08_store_sensitivity, 0);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic struct attribute *srf08_attributes[] = {
40562306a36Sopenharmony_ci	&iio_dev_attr_sensor_max_range.dev_attr.attr,
40662306a36Sopenharmony_ci	&iio_dev_attr_sensor_max_range_available.dev_attr.attr,
40762306a36Sopenharmony_ci	&iio_dev_attr_sensor_sensitivity.dev_attr.attr,
40862306a36Sopenharmony_ci	&iio_dev_attr_sensor_sensitivity_available.dev_attr.attr,
40962306a36Sopenharmony_ci	NULL,
41062306a36Sopenharmony_ci};
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic const struct attribute_group srf08_attribute_group = {
41362306a36Sopenharmony_ci	.attrs = srf08_attributes,
41462306a36Sopenharmony_ci};
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic const struct iio_chan_spec srf08_channels[] = {
41762306a36Sopenharmony_ci	{
41862306a36Sopenharmony_ci		.type = IIO_DISTANCE,
41962306a36Sopenharmony_ci		.info_mask_separate =
42062306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_RAW) |
42162306a36Sopenharmony_ci				BIT(IIO_CHAN_INFO_SCALE),
42262306a36Sopenharmony_ci		.scan_index = 0,
42362306a36Sopenharmony_ci		.scan_type = {
42462306a36Sopenharmony_ci			.sign = 's',
42562306a36Sopenharmony_ci			.realbits = 16,
42662306a36Sopenharmony_ci			.storagebits = 16,
42762306a36Sopenharmony_ci			.endianness = IIO_CPU,
42862306a36Sopenharmony_ci		},
42962306a36Sopenharmony_ci	},
43062306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(1),
43162306a36Sopenharmony_ci};
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic const struct iio_info srf08_info = {
43462306a36Sopenharmony_ci	.read_raw = srf08_read_raw,
43562306a36Sopenharmony_ci	.attrs = &srf08_attribute_group,
43662306a36Sopenharmony_ci};
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci/*
43962306a36Sopenharmony_ci * srf02 don't have an adjustable range or sensitivity,
44062306a36Sopenharmony_ci * so we don't need attributes at all
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_cistatic const struct iio_info srf02_info = {
44362306a36Sopenharmony_ci	.read_raw = srf08_read_raw,
44462306a36Sopenharmony_ci};
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic int srf08_probe(struct i2c_client *client)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	const struct i2c_device_id *id = i2c_client_get_device_id(client);
44962306a36Sopenharmony_ci	struct iio_dev *indio_dev;
45062306a36Sopenharmony_ci	struct srf08_data *data;
45162306a36Sopenharmony_ci	int ret;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter,
45462306a36Sopenharmony_ci					I2C_FUNC_SMBUS_READ_BYTE_DATA |
45562306a36Sopenharmony_ci					I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
45662306a36Sopenharmony_ci					I2C_FUNC_SMBUS_READ_WORD_DATA))
45762306a36Sopenharmony_ci		return -ENODEV;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
46062306a36Sopenharmony_ci	if (!indio_dev)
46162306a36Sopenharmony_ci		return -ENOMEM;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	data = iio_priv(indio_dev);
46462306a36Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
46562306a36Sopenharmony_ci	data->client = client;
46662306a36Sopenharmony_ci	data->sensor_type = (enum srf08_sensor_type)id->driver_data;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	switch (data->sensor_type) {
46962306a36Sopenharmony_ci	case SRF02:
47062306a36Sopenharmony_ci		data->chip_info = &srf02_chip_info;
47162306a36Sopenharmony_ci		indio_dev->info = &srf02_info;
47262306a36Sopenharmony_ci		break;
47362306a36Sopenharmony_ci	case SRF08:
47462306a36Sopenharmony_ci		data->chip_info = &srf08_chip_info;
47562306a36Sopenharmony_ci		indio_dev->info = &srf08_info;
47662306a36Sopenharmony_ci		break;
47762306a36Sopenharmony_ci	case SRF10:
47862306a36Sopenharmony_ci		data->chip_info = &srf10_chip_info;
47962306a36Sopenharmony_ci		indio_dev->info = &srf08_info;
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci	default:
48262306a36Sopenharmony_ci		return -EINVAL;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	indio_dev->name = id->name;
48662306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
48762306a36Sopenharmony_ci	indio_dev->channels = srf08_channels;
48862306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	mutex_init(&data->lock);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
49362306a36Sopenharmony_ci			iio_pollfunc_store_time, srf08_trigger_handler, NULL);
49462306a36Sopenharmony_ci	if (ret < 0) {
49562306a36Sopenharmony_ci		dev_err(&client->dev, "setup of iio triggered buffer failed\n");
49662306a36Sopenharmony_ci		return ret;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (data->chip_info->range_default) {
50062306a36Sopenharmony_ci		/*
50162306a36Sopenharmony_ci		 * set default range of device in mm here
50262306a36Sopenharmony_ci		 * these register values cannot be read from the hardware
50362306a36Sopenharmony_ci		 * therefore set driver specific default values
50462306a36Sopenharmony_ci		 *
50562306a36Sopenharmony_ci		 * srf02 don't have a default value so it'll be omitted
50662306a36Sopenharmony_ci		 */
50762306a36Sopenharmony_ci		ret = srf08_write_range_mm(data,
50862306a36Sopenharmony_ci					data->chip_info->range_default);
50962306a36Sopenharmony_ci		if (ret < 0)
51062306a36Sopenharmony_ci			return ret;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (data->chip_info->sensitivity_default) {
51462306a36Sopenharmony_ci		/*
51562306a36Sopenharmony_ci		 * set default sensitivity of device here
51662306a36Sopenharmony_ci		 * these register values cannot be read from the hardware
51762306a36Sopenharmony_ci		 * therefore set driver specific default values
51862306a36Sopenharmony_ci		 *
51962306a36Sopenharmony_ci		 * srf02 don't have a default value so it'll be omitted
52062306a36Sopenharmony_ci		 */
52162306a36Sopenharmony_ci		ret = srf08_write_sensitivity(data,
52262306a36Sopenharmony_ci				data->chip_info->sensitivity_default);
52362306a36Sopenharmony_ci		if (ret < 0)
52462306a36Sopenharmony_ci			return ret;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic const struct of_device_id of_srf08_match[] = {
53162306a36Sopenharmony_ci	{ .compatible = "devantech,srf02", (void *)SRF02 },
53262306a36Sopenharmony_ci	{ .compatible = "devantech,srf08", (void *)SRF08 },
53362306a36Sopenharmony_ci	{ .compatible = "devantech,srf10", (void *)SRF10 },
53462306a36Sopenharmony_ci	{},
53562306a36Sopenharmony_ci};
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_srf08_match);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic const struct i2c_device_id srf08_id[] = {
54062306a36Sopenharmony_ci	{ "srf02", SRF02 },
54162306a36Sopenharmony_ci	{ "srf08", SRF08 },
54262306a36Sopenharmony_ci	{ "srf10", SRF10 },
54362306a36Sopenharmony_ci	{ }
54462306a36Sopenharmony_ci};
54562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, srf08_id);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic struct i2c_driver srf08_driver = {
54862306a36Sopenharmony_ci	.driver = {
54962306a36Sopenharmony_ci		.name	= "srf08",
55062306a36Sopenharmony_ci		.of_match_table	= of_srf08_match,
55162306a36Sopenharmony_ci	},
55262306a36Sopenharmony_ci	.probe = srf08_probe,
55362306a36Sopenharmony_ci	.id_table = srf08_id,
55462306a36Sopenharmony_ci};
55562306a36Sopenharmony_cimodule_i2c_driver(srf08_driver);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
55862306a36Sopenharmony_ciMODULE_DESCRIPTION("Devantech SRF02/SRF08/SRF10 i2c ultrasonic ranger driver");
55962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
560