File Index
Files and directories
Sign in
FILE

tmp006.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/temperature/tmp006.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * tmp006.c - Support for TI TMP006 IR thermopile sensor
  4 *
  5 * Copyright (c) 2013 Peter Meerwald <pmeerw@pmeerw.net>
  6 *
  7 * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
  8 *
  9 * (7-bit I2C slave address 0x40, changeable via ADR pins)
 10 */
 11
 12#include <linux/err.h>
 13#include <linux/i2c.h>
 14#include <linux/delay.h>
 15#include <linux/module.h>
 16#include <linux/mod_devicetable.h>
 17#include <linux/pm.h>
 18#include <linux/bitops.h>
 19
 20#include <linux/iio/iio.h>
 21#include <linux/iio/sysfs.h>
 22#include <linux/iio/trigger.h>
 23#include <linux/iio/triggered_buffer.h>
 24#include <linux/iio/trigger_consumer.h>
 25
 26#define TMP006_VOBJECT 0x00
 27#define TMP006_TAMBIENT 0x01
 28#define TMP006_CONFIG 0x02
 29#define TMP006_MANUFACTURER_ID 0xfe
 30#define TMP006_DEVICE_ID 0xff
 31
 32#define TMP006_TAMBIENT_SHIFT 2
 33
 34#define TMP006_CONFIG_RESET BIT(15)
 35#define TMP006_CONFIG_DRDY_EN BIT(8)
 36#define TMP006_CONFIG_DRDY BIT(7)
 37
 38#define TMP006_CONFIG_MOD_MASK GENMASK(14, 12)
 39
 40#define TMP006_CONFIG_CR_MASK GENMASK(11, 9)
 41#define TMP006_CONFIG_CR_SHIFT 9
 42
 43#define TMP006_MANUFACTURER_MAGIC 0x5449
 44#define TMP006_DEVICE_MAGIC 0x0067
 45
 46struct tmp006_data {
 47	struct i2c_client *client;
 48	u16 config;
 49	struct iio_trigger *drdy_trig;
 50};
 51
 52static int tmp006_read_measurement(struct tmp006_data *data, u8 reg)
 53{
 54	s32 ret;
 55	int tries = 50;
 56
 57	while (tries-- > 0) {
 58		ret = i2c_smbus_read_word_swapped(data->client,
 59			TMP006_CONFIG);
 60		if (ret < 0)
 61			return ret;
 62		if (ret & TMP006_CONFIG_DRDY)
 63			break;
 64		msleep(100);
 65	}
 66
 67	if (tries < 0)
 68		return -EIO;
 69
 70	return i2c_smbus_read_word_swapped(data->client, reg);
 71}
 72
 73static const int tmp006_freqs[5][2] = { {4, 0}, {2, 0}, {1, 0},
 74					{0, 500000}, {0, 250000} };
 75
 76static int tmp006_read_raw(struct iio_dev *indio_dev,
 77			    struct iio_chan_spec const *channel, int *val,
 78			    int *val2, long mask)
 79{
 80	struct tmp006_data *data = iio_priv(indio_dev);
 81	s32 ret;
 82	int cr;
 83
 84	switch (mask) {
 85	case IIO_CHAN_INFO_RAW:
 86		if (channel->type == IIO_VOLTAGE) {
 87			/* LSB is 156.25 nV */
 88			if (!iio_device_claim_direct(indio_dev))
 89				return -EBUSY;
 90
 91			ret = tmp006_read_measurement(data, TMP006_VOBJECT);
 92			iio_device_release_direct(indio_dev);
 93			if (ret < 0)
 94				return ret;
 95
 96			*val = sign_extend32(ret, 15);
 97		} else if (channel->type == IIO_TEMP) {
 98			/* LSB is 0.03125 degrees Celsius */
 99			if (!iio_device_claim_direct(indio_dev))
100				return -EBUSY;
101
102			ret = tmp006_read_measurement(data, TMP006_TAMBIENT);
103			iio_device_release_direct(indio_dev);
104			if (ret < 0)
105				return ret;
106
107			*val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT;
108		} else {
109			break;
110		}
111		return IIO_VAL_INT;
112	case IIO_CHAN_INFO_SCALE:
113		if (channel->type == IIO_VOLTAGE) {
114			*val = 0;
115			*val2 = 156250;
116		} else if (channel->type == IIO_TEMP) {
117			*val = 31;
118			*val2 = 250000;
119		} else {
120			break;
121		}
122		return IIO_VAL_INT_PLUS_MICRO;
123	case IIO_CHAN_INFO_SAMP_FREQ:
124		cr = (data->config & TMP006_CONFIG_CR_MASK)
125			>> TMP006_CONFIG_CR_SHIFT;
126		*val = tmp006_freqs[cr][0];
127		*val2 = tmp006_freqs[cr][1];
128		return IIO_VAL_INT_PLUS_MICRO;
129	default:
130		break;
131	}
132
133	return -EINVAL;
134}
135
136static int tmp006_write_raw(struct iio_dev *indio_dev,
137			    struct iio_chan_spec const *chan,
138			    int val,
139			    int val2,
140			    long mask)
141{
142	struct tmp006_data *data = iio_priv(indio_dev);
143	int ret, i;
144
145	if (mask != IIO_CHAN_INFO_SAMP_FREQ)
146		return -EINVAL;
147
148	for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++)
149		if ((val == tmp006_freqs[i][0]) &&
150		    (val2 == tmp006_freqs[i][1])) {
151			if (!iio_device_claim_direct(indio_dev))
152				return -EBUSY;
153
154			data->config &= ~TMP006_CONFIG_CR_MASK;
155			data->config |= i << TMP006_CONFIG_CR_SHIFT;
156
157			ret = i2c_smbus_write_word_swapped(data->client,
158							   TMP006_CONFIG,
159							   data->config);
160
161			iio_device_release_direct(indio_dev);
162			return ret;
163		}
164	return -EINVAL;
165}
166
167static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
168
169static struct attribute *tmp006_attributes[] = {
170	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
171	NULL
172};
173
174static const struct attribute_group tmp006_attribute_group = {
175	.attrs = tmp006_attributes,
176};
177
178static const struct iio_chan_spec tmp006_channels[] = {
179	{
180		.type = IIO_VOLTAGE,
181		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
182			BIT(IIO_CHAN_INFO_SCALE),
183		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
184		.scan_index = 0,
185		.scan_type = {
186			.sign = 's',
187			.realbits = 16,
188			.storagebits = 16,
189			.endianness = IIO_BE,
190		}
191	},
192	{
193		.type = IIO_TEMP,
194		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
195			BIT(IIO_CHAN_INFO_SCALE),
196		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
197		.scan_index = 1,
198		.scan_type = {
199			.sign = 's',
200			.realbits = 14,
201			.storagebits = 16,
202			.shift = TMP006_TAMBIENT_SHIFT,
203			.endianness = IIO_BE,
204		}
205	},
206	IIO_CHAN_SOFT_TIMESTAMP(2),
207};
208
209static const struct iio_info tmp006_info = {
210	.read_raw = tmp006_read_raw,
211	.write_raw = tmp006_write_raw,
212	.attrs = &tmp006_attribute_group,
213};
214
215static bool tmp006_check_identification(struct i2c_client *client)
216{
217	int mid, did;
218
219	mid = i2c_smbus_read_word_swapped(client, TMP006_MANUFACTURER_ID);
220	if (mid < 0)
221		return false;
222
223	did = i2c_smbus_read_word_swapped(client, TMP006_DEVICE_ID);
224	if (did < 0)
225		return false;
226
227	return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC;
228}
229
230static int tmp006_power(struct device *dev, bool up)
231{
232	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
233	struct tmp006_data *data = iio_priv(indio_dev);
234
235	if (up)
236		data->config |= TMP006_CONFIG_MOD_MASK;
237	else
238		data->config &= ~TMP006_CONFIG_MOD_MASK;
239
240	return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
241		data->config);
242}
243
244static void tmp006_powerdown_cleanup(void *dev)
245{
246	tmp006_power(dev, false);
247}
248
249static irqreturn_t tmp006_trigger_handler(int irq, void *p)
250{
251	struct iio_poll_func *pf = p;
252	struct iio_dev *indio_dev = pf->indio_dev;
253	struct tmp006_data *data = iio_priv(indio_dev);
254	struct {
255		s16 channels[2];
256		aligned_s64 ts;
257	} scan = { };
258	s32 ret;
259
260	ret = i2c_smbus_read_word_data(data->client, TMP006_VOBJECT);
261	if (ret < 0)
262		goto err;
263	scan.channels[0] = ret;
264
265	ret = i2c_smbus_read_word_data(data->client, TMP006_TAMBIENT);
266	if (ret < 0)
267		goto err;
268	scan.channels[1] = ret;
269
270	iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
271				    iio_get_time_ns(indio_dev));
272err:
273	iio_trigger_notify_done(indio_dev->trig);
274	return IRQ_HANDLED;
275}
276
277static int tmp006_set_trigger_state(struct iio_trigger *trig, bool state)
278{
279	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
280	struct tmp006_data *data = iio_priv(indio_dev);
281
282	if (state)
283		data->config |= TMP006_CONFIG_DRDY_EN;
284	else
285		data->config &= ~TMP006_CONFIG_DRDY_EN;
286
287	return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
288					    data->config);
289}
290
291static const struct iio_trigger_ops tmp006_trigger_ops = {
292	.set_trigger_state = tmp006_set_trigger_state,
293};
294
295static const unsigned long tmp006_scan_masks[] = { 0x3, 0 };
296
297static int tmp006_probe(struct i2c_client *client)
298{
299	struct iio_dev *indio_dev;
300	struct tmp006_data *data;
301	int ret;
302
303	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
304		return -EOPNOTSUPP;
305
306	if (!tmp006_check_identification(client)) {
307		dev_err(&client->dev, "no TMP006 sensor\n");
308		return -ENODEV;
309	}
310
311	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
312	if (!indio_dev)
313		return -ENOMEM;
314
315	data = iio_priv(indio_dev);
316	i2c_set_clientdata(client, indio_dev);
317	data->client = client;
318
319	indio_dev->name = dev_name(&client->dev);
320	indio_dev->modes = INDIO_DIRECT_MODE;
321	indio_dev->info = &tmp006_info;
322
323	indio_dev->channels = tmp006_channels;
324	indio_dev->num_channels = ARRAY_SIZE(tmp006_channels);
325	indio_dev->available_scan_masks = tmp006_scan_masks;
326
327	ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG);
328	if (ret < 0)
329		return ret;
330	data->config = ret;
331
332	if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) {
333		ret = tmp006_power(&client->dev, true);
334		if (ret < 0)
335			return ret;
336	}
337
338	ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup,
339				       &client->dev);
340	if (ret < 0)
341		return ret;
342
343	if (client->irq > 0) {
344		data->drdy_trig = devm_iio_trigger_alloc(&client->dev,
345							 "%s-dev%d",
346							 indio_dev->name,
347							 iio_device_id(indio_dev));
348		if (!data->drdy_trig)
349			return -ENOMEM;
350
351		data->drdy_trig->ops = &tmp006_trigger_ops;
352		iio_trigger_set_drvdata(data->drdy_trig, indio_dev);
353		ret = iio_trigger_register(data->drdy_trig);
354		if (ret)
355			return ret;
356
357		indio_dev->trig = iio_trigger_get(data->drdy_trig);
358
359		ret = devm_request_threaded_irq(&client->dev, client->irq,
360						iio_trigger_generic_data_rdy_poll,
361						NULL,
362						IRQF_ONESHOT,
363						"tmp006_irq",
364						data->drdy_trig);
365		if (ret < 0)
366			return ret;
367	}
368
369	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
370					      tmp006_trigger_handler, NULL);
371	if (ret < 0)
372		return ret;
373
374	return devm_iio_device_register(&client->dev, indio_dev);
375}
376
377static int tmp006_suspend(struct device *dev)
378{
379	return tmp006_power(dev, false);
380}
381
382static int tmp006_resume(struct device *dev)
383{
384	return tmp006_power(dev, true);
385}
386
387static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
388
389static const struct of_device_id tmp006_of_match[] = {
390	{ .compatible = "ti,tmp006" },
391	{ }
392};
393MODULE_DEVICE_TABLE(of, tmp006_of_match);
394
395static const struct i2c_device_id tmp006_id[] = {
396	{ "tmp006" },
397	{ }
398};
399MODULE_DEVICE_TABLE(i2c, tmp006_id);
400
401static struct i2c_driver tmp006_driver = {
402	.driver = {
403		.name	= "tmp006",
404		.of_match_table = tmp006_of_match,
405		.pm	= pm_sleep_ptr(&tmp006_pm_ops),
406	},
407	.probe = tmp006_probe,
408	.id_table = tmp006_id,
409};
410module_i2c_driver(tmp006_driver);
411
412MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
413MODULE_DESCRIPTION("TI TMP006 IR thermopile sensor driver");
414MODULE_LICENSE("GPL");
~/ Read-only file preview.