xref: /openbmc/linux/drivers/iio/proximity/srf08.c (revision 4da722ca)
1 /*
2  * srf08.c - Support for Devantech SRF08 ultrasonic ranger
3  *
4  * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
5  *
6  * This file is subject to the terms and conditions of version 2 of
7  * the GNU General Public License.  See the file COPYING in the main
8  * directory of this archive for more details.
9  *
10  * For details about the device see:
11  * http://www.robot-electronics.co.uk/htm/srf08tech.html
12  */
13 
14 #include <linux/err.h>
15 #include <linux/i2c.h>
16 #include <linux/delay.h>
17 #include <linux/module.h>
18 #include <linux/bitops.h>
19 #include <linux/iio/iio.h>
20 #include <linux/iio/sysfs.h>
21 
22 /* registers of SRF08 device */
23 #define SRF08_WRITE_COMMAND	0x00	/* Command Register */
24 #define SRF08_WRITE_MAX_GAIN	0x01	/* Max Gain Register: 0 .. 31 */
25 #define SRF08_WRITE_RANGE	0x02	/* Range Register: 0 .. 255 */
26 #define SRF08_READ_SW_REVISION	0x00	/* Software Revision */
27 #define SRF08_READ_LIGHT	0x01	/* Light Sensor during last echo */
28 #define SRF08_READ_ECHO_1_HIGH	0x02	/* Range of first echo received */
29 #define SRF08_READ_ECHO_1_LOW	0x03	/* Range of first echo received */
30 
31 #define SRF08_CMD_RANGING_CM	0x51	/* Ranging Mode - Result in cm */
32 
33 #define SRF08_DEFAULT_GAIN	1025	/* default analogue value of Gain */
34 #define SRF08_DEFAULT_RANGE	6020	/* default value of Range in mm */
35 
36 struct srf08_data {
37 	struct i2c_client	*client;
38 	int			sensitivity;		/* Gain */
39 	int			range_mm;		/* max. Range in mm */
40 	struct mutex		lock;
41 };
42 
43 /*
44  * in the documentation one can read about the "Gain" of the device
45  * which is used here for amplifying the signal and filtering out unwanted
46  * ones.
47  * But with ADC's this term is already used differently and that's why it
48  * is called "Sensitivity" here.
49  */
50 static const int srf08_sensitivity[] = {
51 	 94,  97, 100, 103, 107, 110, 114, 118,
52 	123, 128, 133, 139, 145, 152, 159, 168,
53 	177, 187, 199, 212, 227, 245, 265, 288,
54 	317, 352, 395, 450, 524, 626, 777, 1025 };
55 
56 static int srf08_read_ranging(struct srf08_data *data)
57 {
58 	struct i2c_client *client = data->client;
59 	int ret, i;
60 	int waittime;
61 
62 	mutex_lock(&data->lock);
63 
64 	ret = i2c_smbus_write_byte_data(data->client,
65 			SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
66 	if (ret < 0) {
67 		dev_err(&client->dev, "write command - err: %d\n", ret);
68 		mutex_unlock(&data->lock);
69 		return ret;
70 	}
71 
72 	/*
73 	 * we read here until a correct version number shows up as
74 	 * suggested by the documentation
75 	 *
76 	 * with an ultrasonic speed of 343 m/s and a roundtrip of it
77 	 * sleep the expected duration and try to read from the device
78 	 * if nothing useful is read try it in a shorter grid
79 	 *
80 	 * polling for not more than 20 ms should be enough
81 	 */
82 	waittime = 1 + data->range_mm / 172;
83 	msleep(waittime);
84 	for (i = 0; i < 4; i++) {
85 		ret = i2c_smbus_read_byte_data(data->client,
86 						SRF08_READ_SW_REVISION);
87 
88 		/* check if a valid version number is read */
89 		if (ret < 255 && ret > 0)
90 			break;
91 		msleep(5);
92 	}
93 
94 	if (ret >= 255 || ret <= 0) {
95 		dev_err(&client->dev, "device not ready\n");
96 		mutex_unlock(&data->lock);
97 		return -EIO;
98 	}
99 
100 	ret = i2c_smbus_read_word_swapped(data->client,
101 						SRF08_READ_ECHO_1_HIGH);
102 	if (ret < 0) {
103 		dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
104 		mutex_unlock(&data->lock);
105 		return ret;
106 	}
107 
108 	mutex_unlock(&data->lock);
109 
110 	return ret;
111 }
112 
113 static int srf08_read_raw(struct iio_dev *indio_dev,
114 			    struct iio_chan_spec const *channel, int *val,
115 			    int *val2, long mask)
116 {
117 	struct srf08_data *data = iio_priv(indio_dev);
118 	int ret;
119 
120 	if (channel->type != IIO_DISTANCE)
121 		return -EINVAL;
122 
123 	switch (mask) {
124 	case IIO_CHAN_INFO_RAW:
125 		ret = srf08_read_ranging(data);
126 		if (ret < 0)
127 			return ret;
128 		*val = ret;
129 		return IIO_VAL_INT;
130 	case IIO_CHAN_INFO_SCALE:
131 		/* 1 LSB is 1 cm */
132 		*val = 0;
133 		*val2 = 10000;
134 		return IIO_VAL_INT_PLUS_MICRO;
135 	default:
136 		return -EINVAL;
137 	}
138 }
139 
140 static ssize_t srf08_show_range_mm_available(struct device *dev,
141 				struct device_attribute *attr, char *buf)
142 {
143 	return sprintf(buf, "[0.043 0.043 11.008]\n");
144 }
145 
146 static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO,
147 				srf08_show_range_mm_available, NULL, 0);
148 
149 static ssize_t srf08_show_range_mm(struct device *dev,
150 				struct device_attribute *attr, char *buf)
151 {
152 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
153 	struct srf08_data *data = iio_priv(indio_dev);
154 
155 	return sprintf(buf, "%d.%03d\n", data->range_mm / 1000,
156 						data->range_mm % 1000);
157 }
158 
159 /*
160  * set the range of the sensor to an even multiple of 43 mm
161  * which corresponds to 1 LSB in the register
162  *
163  * register value    corresponding range
164  *         0x00             43 mm
165  *         0x01             86 mm
166  *         0x02            129 mm
167  *         ...
168  *         0xFF          11008 mm
169  */
170 static ssize_t srf08_write_range_mm(struct srf08_data *data, unsigned int val)
171 {
172 	int ret;
173 	struct i2c_client *client = data->client;
174 	unsigned int mod;
175 	u8 regval;
176 
177 	ret = val / 43 - 1;
178 	mod = val % 43;
179 
180 	if (mod || (ret < 0) || (ret > 255))
181 		return -EINVAL;
182 
183 	regval = ret;
184 
185 	mutex_lock(&data->lock);
186 
187 	ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_RANGE, regval);
188 	if (ret < 0) {
189 		dev_err(&client->dev, "write_range - err: %d\n", ret);
190 		mutex_unlock(&data->lock);
191 		return ret;
192 	}
193 
194 	data->range_mm = val;
195 
196 	mutex_unlock(&data->lock);
197 
198 	return 0;
199 }
200 
201 static ssize_t srf08_store_range_mm(struct device *dev,
202 					struct device_attribute *attr,
203 					const char *buf, size_t len)
204 {
205 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
206 	struct srf08_data *data = iio_priv(indio_dev);
207 	int ret;
208 	int integer, fract;
209 
210 	ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
211 	if (ret)
212 		return ret;
213 
214 	ret = srf08_write_range_mm(data, integer * 1000 + fract);
215 	if (ret < 0)
216 		return ret;
217 
218 	return len;
219 }
220 
221 static IIO_DEVICE_ATTR(sensor_max_range, S_IRUGO | S_IWUSR,
222 			srf08_show_range_mm, srf08_store_range_mm, 0);
223 
224 static ssize_t srf08_show_sensitivity_available(struct device *dev,
225 				struct device_attribute *attr, char *buf)
226 {
227 	int i, len = 0;
228 
229 	for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
230 		len += sprintf(buf + len, "%d ", srf08_sensitivity[i]);
231 
232 	len += sprintf(buf + len, "\n");
233 
234 	return len;
235 }
236 
237 static IIO_DEVICE_ATTR(sensor_sensitivity_available, S_IRUGO,
238 				srf08_show_sensitivity_available, NULL, 0);
239 
240 static ssize_t srf08_show_sensitivity(struct device *dev,
241 				struct device_attribute *attr, char *buf)
242 {
243 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
244 	struct srf08_data *data = iio_priv(indio_dev);
245 	int len;
246 
247 	len = sprintf(buf, "%d\n", data->sensitivity);
248 
249 	return len;
250 }
251 
252 static ssize_t srf08_write_sensitivity(struct srf08_data *data,
253 							unsigned int val)
254 {
255 	struct i2c_client *client = data->client;
256 	int ret, i;
257 	u8 regval;
258 
259 	for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
260 		if (val == srf08_sensitivity[i]) {
261 			regval = i;
262 			break;
263 		}
264 
265 	if (i >= ARRAY_SIZE(srf08_sensitivity))
266 		return -EINVAL;
267 
268 	mutex_lock(&data->lock);
269 
270 	ret = i2c_smbus_write_byte_data(client,
271 						SRF08_WRITE_MAX_GAIN, regval);
272 	if (ret < 0) {
273 		dev_err(&client->dev, "write_sensitivity - err: %d\n", ret);
274 		mutex_unlock(&data->lock);
275 		return ret;
276 	}
277 
278 	data->sensitivity = val;
279 
280 	mutex_unlock(&data->lock);
281 
282 	return 0;
283 }
284 
285 static ssize_t srf08_store_sensitivity(struct device *dev,
286 						struct device_attribute *attr,
287 						const char *buf, size_t len)
288 {
289 	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
290 	struct srf08_data *data = iio_priv(indio_dev);
291 	int ret;
292 	unsigned int val;
293 
294 	ret = kstrtouint(buf, 10, &val);
295 	if (ret)
296 		return ret;
297 
298 	ret = srf08_write_sensitivity(data, val);
299 	if (ret < 0)
300 		return ret;
301 
302 	return len;
303 }
304 
305 static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
306 			srf08_show_sensitivity, srf08_store_sensitivity, 0);
307 
308 static struct attribute *srf08_attributes[] = {
309 	&iio_dev_attr_sensor_max_range.dev_attr.attr,
310 	&iio_dev_attr_sensor_max_range_available.dev_attr.attr,
311 	&iio_dev_attr_sensor_sensitivity.dev_attr.attr,
312 	&iio_dev_attr_sensor_sensitivity_available.dev_attr.attr,
313 	NULL,
314 };
315 
316 static const struct attribute_group srf08_attribute_group = {
317 	.attrs = srf08_attributes,
318 };
319 
320 static const struct iio_chan_spec srf08_channels[] = {
321 	{
322 		.type = IIO_DISTANCE,
323 		.info_mask_separate =
324 				BIT(IIO_CHAN_INFO_RAW) |
325 				BIT(IIO_CHAN_INFO_SCALE),
326 	},
327 };
328 
329 static const struct iio_info srf08_info = {
330 	.read_raw = srf08_read_raw,
331 	.attrs = &srf08_attribute_group,
332 	.driver_module = THIS_MODULE,
333 };
334 
335 static int srf08_probe(struct i2c_client *client,
336 					 const struct i2c_device_id *id)
337 {
338 	struct iio_dev *indio_dev;
339 	struct srf08_data *data;
340 	int ret;
341 
342 	if (!i2c_check_functionality(client->adapter,
343 					I2C_FUNC_SMBUS_READ_BYTE_DATA |
344 					I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
345 					I2C_FUNC_SMBUS_READ_WORD_DATA))
346 		return -ENODEV;
347 
348 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
349 	if (!indio_dev)
350 		return -ENOMEM;
351 
352 	data = iio_priv(indio_dev);
353 	i2c_set_clientdata(client, indio_dev);
354 	data->client = client;
355 
356 	indio_dev->name = "srf08";
357 	indio_dev->dev.parent = &client->dev;
358 	indio_dev->modes = INDIO_DIRECT_MODE;
359 	indio_dev->info = &srf08_info;
360 	indio_dev->channels = srf08_channels;
361 	indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
362 
363 	mutex_init(&data->lock);
364 
365 	/*
366 	 * set default values of device here
367 	 * these register values cannot be read from the hardware
368 	 * therefore set driver specific default values
369 	 */
370 	ret = srf08_write_range_mm(data, SRF08_DEFAULT_RANGE);
371 	if (ret < 0)
372 		return ret;
373 
374 	ret = srf08_write_sensitivity(data, SRF08_DEFAULT_GAIN);
375 	if (ret < 0)
376 		return ret;
377 
378 	return devm_iio_device_register(&client->dev, indio_dev);
379 }
380 
381 static const struct i2c_device_id srf08_id[] = {
382 	{ "srf08", 0 },
383 	{ }
384 };
385 MODULE_DEVICE_TABLE(i2c, srf08_id);
386 
387 static struct i2c_driver srf08_driver = {
388 	.driver = {
389 		.name	= "srf08",
390 	},
391 	.probe = srf08_probe,
392 	.id_table = srf08_id,
393 };
394 module_i2c_driver(srf08_driver);
395 
396 MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
397 MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver");
398 MODULE_LICENSE("GPL");
399