xref: /linux/drivers/iio/temperature/tmp006.c (revision f879306834818ebd1722a4372079610cdd466fec)
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  * TODO: data ready irq
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/mod_devicetable.h>
19 #include <linux/pm.h>
20 #include <linux/bitops.h>
21 
22 #include <linux/iio/iio.h>
23 #include <linux/iio/sysfs.h>
24 
25 #define TMP006_VOBJECT 0x00
26 #define TMP006_TAMBIENT 0x01
27 #define TMP006_CONFIG 0x02
28 #define TMP006_MANUFACTURER_ID 0xfe
29 #define TMP006_DEVICE_ID 0xff
30 
31 #define TMP006_TAMBIENT_SHIFT 2
32 
33 #define TMP006_CONFIG_RESET BIT(15)
34 #define TMP006_CONFIG_DRDY_EN BIT(8)
35 #define TMP006_CONFIG_DRDY BIT(7)
36 
37 #define TMP006_CONFIG_MOD_MASK GENMASK(14, 12)
38 
39 #define TMP006_CONFIG_CR_MASK GENMASK(11, 9)
40 #define TMP006_CONFIG_CR_SHIFT 9
41 
42 #define TMP006_MANUFACTURER_MAGIC 0x5449
43 #define TMP006_DEVICE_MAGIC 0x0067
44 
45 struct tmp006_data {
46 	struct i2c_client *client;
47 	u16 config;
48 };
49 
50 static int tmp006_read_measurement(struct tmp006_data *data, u8 reg)
51 {
52 	s32 ret;
53 	int tries = 50;
54 
55 	while (tries-- > 0) {
56 		ret = i2c_smbus_read_word_swapped(data->client,
57 			TMP006_CONFIG);
58 		if (ret < 0)
59 			return ret;
60 		if (ret & TMP006_CONFIG_DRDY)
61 			break;
62 		msleep(100);
63 	}
64 
65 	if (tries < 0)
66 		return -EIO;
67 
68 	return i2c_smbus_read_word_swapped(data->client, reg);
69 }
70 
71 static const int tmp006_freqs[5][2] = { {4, 0}, {2, 0}, {1, 0},
72 					{0, 500000}, {0, 250000} };
73 
74 static int tmp006_read_raw(struct iio_dev *indio_dev,
75 			    struct iio_chan_spec const *channel, int *val,
76 			    int *val2, long mask)
77 {
78 	struct tmp006_data *data = iio_priv(indio_dev);
79 	s32 ret;
80 	int cr;
81 
82 	switch (mask) {
83 	case IIO_CHAN_INFO_RAW:
84 		if (channel->type == IIO_VOLTAGE) {
85 			/* LSB is 156.25 nV */
86 			ret = tmp006_read_measurement(data, TMP006_VOBJECT);
87 			if (ret < 0)
88 				return ret;
89 			*val = sign_extend32(ret, 15);
90 		} else if (channel->type == IIO_TEMP) {
91 			/* LSB is 0.03125 degrees Celsius */
92 			ret = tmp006_read_measurement(data, TMP006_TAMBIENT);
93 			if (ret < 0)
94 				return ret;
95 			*val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT;
96 		} else {
97 			break;
98 		}
99 		return IIO_VAL_INT;
100 	case IIO_CHAN_INFO_SCALE:
101 		if (channel->type == IIO_VOLTAGE) {
102 			*val = 0;
103 			*val2 = 156250;
104 		} else if (channel->type == IIO_TEMP) {
105 			*val = 31;
106 			*val2 = 250000;
107 		} else {
108 			break;
109 		}
110 		return IIO_VAL_INT_PLUS_MICRO;
111 	case IIO_CHAN_INFO_SAMP_FREQ:
112 		cr = (data->config & TMP006_CONFIG_CR_MASK)
113 			>> TMP006_CONFIG_CR_SHIFT;
114 		*val = tmp006_freqs[cr][0];
115 		*val2 = tmp006_freqs[cr][1];
116 		return IIO_VAL_INT_PLUS_MICRO;
117 	default:
118 		break;
119 	}
120 
121 	return -EINVAL;
122 }
123 
124 static int tmp006_write_raw(struct iio_dev *indio_dev,
125 			    struct iio_chan_spec const *chan,
126 			    int val,
127 			    int val2,
128 			    long mask)
129 {
130 	struct tmp006_data *data = iio_priv(indio_dev);
131 	int i;
132 
133 	if (mask != IIO_CHAN_INFO_SAMP_FREQ)
134 		return -EINVAL;
135 
136 	for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++)
137 		if ((val == tmp006_freqs[i][0]) &&
138 		    (val2 == tmp006_freqs[i][1])) {
139 			data->config &= ~TMP006_CONFIG_CR_MASK;
140 			data->config |= i << TMP006_CONFIG_CR_SHIFT;
141 
142 			return i2c_smbus_write_word_swapped(data->client,
143 							    TMP006_CONFIG,
144 							    data->config);
145 
146 		}
147 	return -EINVAL;
148 }
149 
150 static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
151 
152 static struct attribute *tmp006_attributes[] = {
153 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
154 	NULL
155 };
156 
157 static const struct attribute_group tmp006_attribute_group = {
158 	.attrs = tmp006_attributes,
159 };
160 
161 static const struct iio_chan_spec tmp006_channels[] = {
162 	{
163 		.type = IIO_VOLTAGE,
164 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
165 			BIT(IIO_CHAN_INFO_SCALE),
166 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
167 	},
168 	{
169 		.type = IIO_TEMP,
170 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
171 			BIT(IIO_CHAN_INFO_SCALE),
172 		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
173 	}
174 };
175 
176 static const struct iio_info tmp006_info = {
177 	.read_raw = tmp006_read_raw,
178 	.write_raw = tmp006_write_raw,
179 	.attrs = &tmp006_attribute_group,
180 };
181 
182 static bool tmp006_check_identification(struct i2c_client *client)
183 {
184 	int mid, did;
185 
186 	mid = i2c_smbus_read_word_swapped(client, TMP006_MANUFACTURER_ID);
187 	if (mid < 0)
188 		return false;
189 
190 	did = i2c_smbus_read_word_swapped(client, TMP006_DEVICE_ID);
191 	if (did < 0)
192 		return false;
193 
194 	return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC;
195 }
196 
197 static int tmp006_power(struct device *dev, bool up)
198 {
199 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
200 	struct tmp006_data *data = iio_priv(indio_dev);
201 
202 	if (up)
203 		data->config |= TMP006_CONFIG_MOD_MASK;
204 	else
205 		data->config &= ~TMP006_CONFIG_MOD_MASK;
206 
207 	return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG,
208 		data->config);
209 }
210 
211 static void tmp006_powerdown_cleanup(void *dev)
212 {
213 	tmp006_power(dev, false);
214 }
215 
216 static int tmp006_probe(struct i2c_client *client)
217 {
218 	struct iio_dev *indio_dev;
219 	struct tmp006_data *data;
220 	int ret;
221 
222 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
223 		return -EOPNOTSUPP;
224 
225 	if (!tmp006_check_identification(client)) {
226 		dev_err(&client->dev, "no TMP006 sensor\n");
227 		return -ENODEV;
228 	}
229 
230 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
231 	if (!indio_dev)
232 		return -ENOMEM;
233 
234 	data = iio_priv(indio_dev);
235 	i2c_set_clientdata(client, indio_dev);
236 	data->client = client;
237 
238 	indio_dev->name = dev_name(&client->dev);
239 	indio_dev->modes = INDIO_DIRECT_MODE;
240 	indio_dev->info = &tmp006_info;
241 
242 	indio_dev->channels = tmp006_channels;
243 	indio_dev->num_channels = ARRAY_SIZE(tmp006_channels);
244 
245 	ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG);
246 	if (ret < 0)
247 		return ret;
248 	data->config = ret;
249 
250 	if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) {
251 		ret = tmp006_power(&client->dev, true);
252 		if (ret < 0)
253 			return ret;
254 	}
255 
256 	ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup,
257 				       &client->dev);
258 	if (ret < 0)
259 		return ret;
260 
261 	return devm_iio_device_register(&client->dev, indio_dev);
262 }
263 
264 static int tmp006_suspend(struct device *dev)
265 {
266 	return tmp006_power(dev, false);
267 }
268 
269 static int tmp006_resume(struct device *dev)
270 {
271 	return tmp006_power(dev, true);
272 }
273 
274 static DEFINE_SIMPLE_DEV_PM_OPS(tmp006_pm_ops, tmp006_suspend, tmp006_resume);
275 
276 static const struct of_device_id tmp006_of_match[] = {
277 	{ .compatible = "ti,tmp006" },
278 	{ }
279 };
280 MODULE_DEVICE_TABLE(of, tmp006_of_match);
281 
282 static const struct i2c_device_id tmp006_id[] = {
283 	{ "tmp006" },
284 	{ }
285 };
286 MODULE_DEVICE_TABLE(i2c, tmp006_id);
287 
288 static struct i2c_driver tmp006_driver = {
289 	.driver = {
290 		.name	= "tmp006",
291 		.of_match_table = tmp006_of_match,
292 		.pm	= pm_sleep_ptr(&tmp006_pm_ops),
293 	},
294 	.probe = tmp006_probe,
295 	.id_table = tmp006_id,
296 };
297 module_i2c_driver(tmp006_driver);
298 
299 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
300 MODULE_DESCRIPTION("TI TMP006 IR thermopile sensor driver");
301 MODULE_LICENSE("GPL");
302