File Index
Files and directories
Sign in
FILE

ad7816.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/iio/adc/ad7816.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * AD7816 digital temperature sensor driver supporting AD7816/7/8
  4 *
  5 * Copyright 2010 Analog Devices Inc.
  6 */
  7
  8#include <linux/interrupt.h>
  9#include <linux/gpio/consumer.h>
 10#include <linux/device.h>
 11#include <linux/kernel.h>
 12#include <linux/slab.h>
 13#include <linux/sysfs.h>
 14#include <linux/list.h>
 15#include <linux/spi/spi.h>
 16#include <linux/module.h>
 17
 18#include <linux/iio/iio.h>
 19#include <linux/iio/sysfs.h>
 20#include <linux/iio/events.h>
 21
 22/*
 23 * AD7816 config masks
 24 */
 25#define AD7816_FULL			0x1
 26#define AD7816_PD			0x2
 27#define AD7816_CS_MASK			0x7
 28#define AD7816_CS_MAX			0x4
 29
 30/*
 31 * AD7816 temperature masks
 32 */
 33#define AD7816_VALUE_OFFSET		6
 34#define AD7816_BOUND_VALUE_BASE		0x8
 35#define AD7816_BOUND_VALUE_MIN		-95
 36#define AD7816_BOUND_VALUE_MAX		152
 37#define AD7816_TEMP_FLOAT_OFFSET	2
 38#define AD7816_TEMP_FLOAT_MASK		0x3
 39
 40/*
 41 * struct ad7816_chip_info - chip specific information
 42 */
 43
 44struct ad7816_chip_info {
 45	kernel_ulong_t id;
 46	struct spi_device *spi_dev;
 47	struct gpio_desc *rdwr_pin;
 48	struct gpio_desc *convert_pin;
 49	struct gpio_desc *busy_pin;
 50	u8  oti_data[AD7816_CS_MAX + 1];
 51	u8  channel_id;	/* 0 always be temperature */
 52	u8  mode;
 53};
 54
 55enum ad7816_type {
 56	ID_AD7816,
 57	ID_AD7817,
 58	ID_AD7818,
 59};
 60
 61/*
 62 * ad7816 data access by SPI
 63 */
 64static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
 65{
 66	struct spi_device *spi_dev = chip->spi_dev;
 67	int ret;
 68	__be16 buf;
 69
 70	gpiod_set_value(chip->rdwr_pin, 1);
 71	gpiod_set_value(chip->rdwr_pin, 0);
 72	ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
 73	if (ret < 0) {
 74		dev_err(&spi_dev->dev, "SPI channel setting error\n");
 75		return ret;
 76	}
 77	gpiod_set_value(chip->rdwr_pin, 1);
 78
 79	if (chip->mode == AD7816_PD) { /* operating mode 2 */
 80		gpiod_set_value(chip->convert_pin, 1);
 81		gpiod_set_value(chip->convert_pin, 0);
 82	} else { /* operating mode 1 */
 83		gpiod_set_value(chip->convert_pin, 0);
 84		gpiod_set_value(chip->convert_pin, 1);
 85	}
 86
 87	if (chip->id == ID_AD7816 || chip->id == ID_AD7817) {
 88		while (gpiod_get_value(chip->busy_pin))
 89			cpu_relax();
 90	}
 91
 92	gpiod_set_value(chip->rdwr_pin, 0);
 93	gpiod_set_value(chip->rdwr_pin, 1);
 94	ret = spi_read(spi_dev, &buf, sizeof(*data));
 95	if (ret < 0) {
 96		dev_err(&spi_dev->dev, "SPI data read error\n");
 97		return ret;
 98	}
 99
100	*data = be16_to_cpu(buf);
101
102	return ret;
103}
104
105static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
106{
107	struct spi_device *spi_dev = chip->spi_dev;
108	int ret;
109
110	gpiod_set_value(chip->rdwr_pin, 1);
111	gpiod_set_value(chip->rdwr_pin, 0);
112	ret = spi_write(spi_dev, &data, sizeof(data));
113	if (ret < 0)
114		dev_err(&spi_dev->dev, "SPI oti data write error\n");
115
116	return ret;
117}
118
119static ssize_t ad7816_show_mode(struct device *dev,
120				struct device_attribute *attr,
121				char *buf)
122{
123	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
124	struct ad7816_chip_info *chip = iio_priv(indio_dev);
125
126	if (chip->mode)
127		return sprintf(buf, "power-save\n");
128	return sprintf(buf, "full\n");
129}
130
131static ssize_t ad7816_store_mode(struct device *dev,
132				 struct device_attribute *attr,
133				 const char *buf,
134				 size_t len)
135{
136	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
137	struct ad7816_chip_info *chip = iio_priv(indio_dev);
138
139	if (strcmp(buf, "full") == 0) {
140		gpiod_set_value(chip->rdwr_pin, 1);
141		chip->mode = AD7816_FULL;
142	} else {
143		gpiod_set_value(chip->rdwr_pin, 0);
144		chip->mode = AD7816_PD;
145	}
146
147	return len;
148}
149
150static IIO_DEVICE_ATTR(mode, 0644,
151		ad7816_show_mode,
152		ad7816_store_mode,
153		0);
154
155static ssize_t ad7816_show_available_modes(struct device *dev,
156					   struct device_attribute *attr,
157					   char *buf)
158{
159	return sprintf(buf, "full\npower-save\n");
160}
161
162static IIO_DEVICE_ATTR(available_modes, 0444, ad7816_show_available_modes,
163			NULL, 0);
164
165static ssize_t ad7816_show_channel(struct device *dev,
166				   struct device_attribute *attr,
167				   char *buf)
168{
169	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
170	struct ad7816_chip_info *chip = iio_priv(indio_dev);
171
172	return sprintf(buf, "%d\n", chip->channel_id);
173}
174
175static ssize_t ad7816_store_channel(struct device *dev,
176				    struct device_attribute *attr,
177				    const char *buf,
178				    size_t len)
179{
180	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
181	struct ad7816_chip_info *chip = iio_priv(indio_dev);
182	unsigned long data;
183	int ret;
184
185	ret = kstrtoul(buf, 10, &data);
186	if (ret)
187		return ret;
188
189	if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) {
190		dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n",
191			data, indio_dev->name);
192		return -EINVAL;
193	} else if (strcmp(indio_dev->name, "ad7818") == 0 && data > 1) {
194		dev_err(&chip->spi_dev->dev,
195			"Invalid channel id %lu for ad7818.\n", data);
196		return -EINVAL;
197	} else if (strcmp(indio_dev->name, "ad7816") == 0 && data > 0) {
198		dev_err(&chip->spi_dev->dev,
199			"Invalid channel id %lu for ad7816.\n", data);
200		return -EINVAL;
201	}
202
203	chip->channel_id = data;
204
205	return len;
206}
207
208static IIO_DEVICE_ATTR(channel, 0644,
209		ad7816_show_channel,
210		ad7816_store_channel,
211		0);
212
213static ssize_t ad7816_show_value(struct device *dev,
214				 struct device_attribute *attr,
215				 char *buf)
216{
217	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
218	struct ad7816_chip_info *chip = iio_priv(indio_dev);
219	u16 data;
220	s8 value;
221	int ret;
222
223	ret = ad7816_spi_read(chip, &data);
224	if (ret)
225		return -EIO;
226
227	data >>= AD7816_VALUE_OFFSET;
228
229	if (chip->channel_id == 0) {
230		value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103);
231		data &= AD7816_TEMP_FLOAT_MASK;
232		if (value < 0)
233			data = BIT(AD7816_TEMP_FLOAT_OFFSET) - data;
234		return sprintf(buf, "%d.%.2d\n", value, data * 25);
235	}
236	return sprintf(buf, "%u\n", data);
237}
238
239static IIO_DEVICE_ATTR(value, 0444, ad7816_show_value, NULL, 0);
240
241static struct attribute *ad7816_attributes[] = {
242	&iio_dev_attr_available_modes.dev_attr.attr,
243	&iio_dev_attr_mode.dev_attr.attr,
244	&iio_dev_attr_channel.dev_attr.attr,
245	&iio_dev_attr_value.dev_attr.attr,
246	NULL,
247};
248
249static const struct attribute_group ad7816_attribute_group = {
250	.attrs = ad7816_attributes,
251};
252
253/*
254 * temperature bound events
255 */
256
257#define IIO_EVENT_CODE_AD7816_OTI IIO_UNMOD_EVENT_CODE(IIO_TEMP,	\
258						       0,		\
259						       IIO_EV_TYPE_THRESH, \
260						       IIO_EV_DIR_FALLING)
261
262static irqreturn_t ad7816_event_handler(int irq, void *private)
263{
264	iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI,
265		       iio_get_time_ns(private));
266	return IRQ_HANDLED;
267}
268
269static ssize_t ad7816_show_oti(struct device *dev,
270			       struct device_attribute *attr,
271			       char *buf)
272{
273	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
274	struct ad7816_chip_info *chip = iio_priv(indio_dev);
275	int value;
276
277	if (chip->channel_id > AD7816_CS_MAX) {
278		dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
279		return -EINVAL;
280	} else if (chip->channel_id == 0) {
281		value = AD7816_BOUND_VALUE_MIN +
282			(chip->oti_data[chip->channel_id] -
283			AD7816_BOUND_VALUE_BASE);
284		return sprintf(buf, "%d\n", value);
285	}
286	return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]);
287}
288
289static inline ssize_t ad7816_set_oti(struct device *dev,
290				     struct device_attribute *attr,
291				     const char *buf,
292				     size_t len)
293{
294	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
295	struct ad7816_chip_info *chip = iio_priv(indio_dev);
296	long value;
297	u8 data;
298	int ret;
299
300	ret = kstrtol(buf, 10, &value);
301	if (ret)
302		return ret;
303
304	if (chip->channel_id > AD7816_CS_MAX) {
305		dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
306		return -EINVAL;
307	} else if (chip->channel_id == 0) {
308		if (value < AD7816_BOUND_VALUE_MIN ||
309		    value > AD7816_BOUND_VALUE_MAX)
310			return -EINVAL;
311
312		data = (u8)(value - AD7816_BOUND_VALUE_MIN +
313			AD7816_BOUND_VALUE_BASE);
314	} else {
315		if (value < AD7816_BOUND_VALUE_BASE || value > 255)
316			return -EINVAL;
317
318		data = (u8)value;
319	}
320
321	ret = ad7816_spi_write(chip, data);
322	if (ret)
323		return -EIO;
324
325	chip->oti_data[chip->channel_id] = data;
326
327	return len;
328}
329
330static IIO_DEVICE_ATTR(oti, 0644,
331		       ad7816_show_oti, ad7816_set_oti, 0);
332
333static struct attribute *ad7816_event_attributes[] = {
334	&iio_dev_attr_oti.dev_attr.attr,
335	NULL,
336};
337
338static const struct attribute_group ad7816_event_attribute_group = {
339	.attrs = ad7816_event_attributes,
340	.name = "events",
341};
342
343static const struct iio_info ad7816_info = {
344	.attrs = &ad7816_attribute_group,
345	.event_attrs = &ad7816_event_attribute_group,
346};
347
348/*
349 * device probe and remove
350 */
351
352static int ad7816_probe(struct spi_device *spi_dev)
353{
354	struct ad7816_chip_info *chip;
355	struct iio_dev *indio_dev;
356	int i, ret;
357
358	indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip));
359	if (!indio_dev)
360		return -ENOMEM;
361	chip = iio_priv(indio_dev);
362
363	chip->spi_dev = spi_dev;
364	for (i = 0; i <= AD7816_CS_MAX; i++)
365		chip->oti_data[i] = 203;
366
367	chip->id = spi_get_device_id(spi_dev)->driver_data;
368	chip->rdwr_pin = devm_gpiod_get(&spi_dev->dev, "rdwr", GPIOD_OUT_HIGH);
369	if (IS_ERR(chip->rdwr_pin)) {
370		ret = PTR_ERR(chip->rdwr_pin);
371		dev_err(&spi_dev->dev, "Failed to request rdwr GPIO: %d\n",
372			ret);
373		return ret;
374	}
375	chip->convert_pin = devm_gpiod_get(&spi_dev->dev, "convert",
376					   GPIOD_OUT_HIGH);
377	if (IS_ERR(chip->convert_pin)) {
378		ret = PTR_ERR(chip->convert_pin);
379		dev_err(&spi_dev->dev, "Failed to request convert GPIO: %d\n",
380			ret);
381		return ret;
382	}
383	if (chip->id == ID_AD7816 || chip->id == ID_AD7817) {
384		chip->busy_pin = devm_gpiod_get(&spi_dev->dev, "busy",
385						GPIOD_IN);
386		if (IS_ERR(chip->busy_pin)) {
387			ret = PTR_ERR(chip->busy_pin);
388			dev_err(&spi_dev->dev, "Failed to request busy GPIO: %d\n",
389				ret);
390			return ret;
391		}
392	}
393
394	indio_dev->name = spi_get_device_id(spi_dev)->name;
395	indio_dev->info = &ad7816_info;
396	indio_dev->modes = INDIO_DIRECT_MODE;
397
398	if (spi_dev->irq) {
399		/* Only low trigger is supported in ad7816/7/8 */
400		ret = devm_request_threaded_irq(&spi_dev->dev, spi_dev->irq,
401						NULL,
402						&ad7816_event_handler,
403						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
404						indio_dev->name,
405						indio_dev);
406		if (ret)
407			return ret;
408	}
409
410	ret = devm_iio_device_register(&spi_dev->dev, indio_dev);
411	if (ret)
412		return ret;
413
414	dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
415		 indio_dev->name);
416
417	return 0;
418}
419
420static const struct of_device_id ad7816_of_match[] = {
421	{ .compatible = "adi,ad7816", },
422	{ .compatible = "adi,ad7817", },
423	{ .compatible = "adi,ad7818", },
424	{ }
425};
426MODULE_DEVICE_TABLE(of, ad7816_of_match);
427
428static const struct spi_device_id ad7816_id[] = {
429	{ "ad7816", ID_AD7816 },
430	{ "ad7817", ID_AD7817 },
431	{ "ad7818", ID_AD7818 },
432	{ }
433};
434
435MODULE_DEVICE_TABLE(spi, ad7816_id);
436
437static struct spi_driver ad7816_driver = {
438	.driver = {
439		.name = "ad7816",
440		.of_match_table = ad7816_of_match,
441	},
442	.probe = ad7816_probe,
443	.id_table = ad7816_id,
444};
445module_spi_driver(ad7816_driver);
446
447MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
448MODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital temperature sensor driver");
449MODULE_LICENSE("GPL v2");
~/ Read-only file preview.