1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * mlx90614.c - Support for Melexis MLX90614/MLX90615 contactless IR temperature sensor |
4 | * |
5 | * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> |
6 | * Copyright (c) 2015 Essensium NV |
7 | * Copyright (c) 2015 Melexis |
8 | * |
9 | * Driver for the Melexis MLX90614/MLX90615 I2C 16-bit IR thermopile sensor |
10 | * |
11 | * MLX90614 - 17-bit ADC + MLX90302 DSP |
12 | * MLX90615 - 16-bit ADC + MLX90325 DSP |
13 | * |
14 | * (7-bit I2C slave address 0x5a, 100KHz bus speed only!) |
15 | * |
16 | * To wake up from sleep mode, the SDA line must be held low while SCL is high |
17 | * for at least 33ms. This is achieved with an extra GPIO that can be connected |
18 | * directly to the SDA line. In normal operation, the GPIO is set as input and |
19 | * will not interfere in I2C communication. While the GPIO is driven low, the |
20 | * i2c adapter is locked since it cannot be used by other clients. The SCL line |
21 | * always has a pull-up so we do not need an extra GPIO to drive it high. If |
22 | * the "wakeup" GPIO is not given, power management will be disabled. |
23 | */ |
24 | |
25 | #include <linux/delay.h> |
26 | #include <linux/err.h> |
27 | #include <linux/gpio/consumer.h> |
28 | #include <linux/i2c.h> |
29 | #include <linux/jiffies.h> |
30 | #include <linux/mod_devicetable.h> |
31 | #include <linux/module.h> |
32 | #include <linux/pm_runtime.h> |
33 | |
34 | #include <linux/iio/iio.h> |
35 | #include <linux/iio/sysfs.h> |
36 | |
37 | #define MLX90614_OP_RAM 0x00 |
38 | #define MLX90614_OP_EEPROM 0x20 |
39 | #define MLX90614_OP_SLEEP 0xff |
40 | |
41 | #define MLX90615_OP_EEPROM 0x10 |
42 | #define MLX90615_OP_RAM 0x20 |
43 | #define MLX90615_OP_SLEEP 0xc6 |
44 | |
45 | /* Control bits in configuration register */ |
46 | #define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */ |
47 | #define MLX90614_CONFIG_IIR_MASK (0x7 << MLX90614_CONFIG_IIR_SHIFT) |
48 | #define MLX90614_CONFIG_DUAL_SHIFT 6 /* single (0) or dual (1) IR sensor */ |
49 | #define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT) |
50 | #define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */ |
51 | #define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT) |
52 | |
53 | #define MLX90615_CONFIG_IIR_SHIFT 12 /* IIR coefficient */ |
54 | #define MLX90615_CONFIG_IIR_MASK (0x7 << MLX90615_CONFIG_IIR_SHIFT) |
55 | |
56 | /* Timings (in ms) */ |
57 | #define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */ |
58 | #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */ |
59 | #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */ |
60 | |
61 | #define MLX90615_TIMING_WAKEUP 22 /* time to hold SCL low for wake-up */ |
62 | |
63 | #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */ |
64 | |
65 | /* Magic constants */ |
66 | #define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */ |
67 | #define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */ |
68 | #define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ |
69 | #define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */ |
70 | |
71 | /* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ |
72 | #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) |
73 | #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) |
74 | |
75 | struct mlx_chip_info { |
76 | /* EEPROM offsets with 16-bit data, MSB first */ |
77 | /* emissivity correction coefficient */ |
78 | u8 op_eeprom_emissivity; |
79 | u8 op_eeprom_config1; |
80 | /* RAM offsets with 16-bit data, MSB first */ |
81 | /* ambient temperature */ |
82 | u8 op_ram_ta; |
83 | /* object 1 temperature */ |
84 | u8 op_ram_tobj1; |
85 | /* object 2 temperature */ |
86 | u8 op_ram_tobj2; |
87 | u8 op_sleep; |
88 | /* support for two input channels (MLX90614 only) */ |
89 | u8 dual_channel; |
90 | u8 wakeup_delay_ms; |
91 | u16 emissivity_max; |
92 | u16 fir_config_mask; |
93 | u16 iir_config_mask; |
94 | int iir_valid_offset; |
95 | u16 iir_values[8]; |
96 | int iir_freqs[8][2]; |
97 | }; |
98 | |
99 | struct mlx90614_data { |
100 | struct i2c_client *client; |
101 | struct mutex lock; /* for EEPROM access only */ |
102 | struct gpio_desc *wakeup_gpio; /* NULL to disable sleep/wake-up */ |
103 | const struct mlx_chip_info *chip_info; /* Chip hardware details */ |
104 | unsigned long ready_timestamp; /* in jiffies */ |
105 | }; |
106 | |
107 | /* |
108 | * Erase an address and write word. |
109 | * The mutex must be locked before calling. |
110 | */ |
111 | static s32 mlx90614_write_word(const struct i2c_client *client, u8 command, |
112 | u16 value) |
113 | { |
114 | /* |
115 | * Note: The mlx90614 requires a PEC on writing but does not send us a |
116 | * valid PEC on reading. Hence, we cannot set I2C_CLIENT_PEC in |
117 | * i2c_client.flags. As a workaround, we use i2c_smbus_xfer here. |
118 | */ |
119 | union i2c_smbus_data data; |
120 | s32 ret; |
121 | |
122 | dev_dbg(&client->dev, "Writing 0x%x to address 0x%x" , value, command); |
123 | |
124 | data.word = 0x0000; /* erase command */ |
125 | ret = i2c_smbus_xfer(adapter: client->adapter, addr: client->addr, |
126 | flags: client->flags | I2C_CLIENT_PEC, |
127 | I2C_SMBUS_WRITE, command, |
128 | I2C_SMBUS_WORD_DATA, data: &data); |
129 | if (ret < 0) |
130 | return ret; |
131 | |
132 | msleep(MLX90614_TIMING_EEPROM); |
133 | |
134 | data.word = value; /* actual write */ |
135 | ret = i2c_smbus_xfer(adapter: client->adapter, addr: client->addr, |
136 | flags: client->flags | I2C_CLIENT_PEC, |
137 | I2C_SMBUS_WRITE, command, |
138 | I2C_SMBUS_WORD_DATA, data: &data); |
139 | |
140 | msleep(MLX90614_TIMING_EEPROM); |
141 | |
142 | return ret; |
143 | } |
144 | |
145 | /* |
146 | * Find the IIR value inside iir_values array and return its position |
147 | * which is equivalent to the bit value in sensor register |
148 | */ |
149 | static inline s32 mlx90614_iir_search(const struct i2c_client *client, |
150 | int value) |
151 | { |
152 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
153 | struct mlx90614_data *data = iio_priv(indio_dev); |
154 | const struct mlx_chip_info *chip_info = data->chip_info; |
155 | int i; |
156 | s32 ret; |
157 | |
158 | for (i = chip_info->iir_valid_offset; |
159 | i < ARRAY_SIZE(chip_info->iir_values); |
160 | i++) { |
161 | if (value == chip_info->iir_values[i]) |
162 | break; |
163 | } |
164 | |
165 | if (i == ARRAY_SIZE(chip_info->iir_values)) |
166 | return -EINVAL; |
167 | |
168 | /* |
169 | * CONFIG register values must not be changed so |
170 | * we must read them before we actually write |
171 | * changes |
172 | */ |
173 | ret = i2c_smbus_read_word_data(client, command: chip_info->op_eeprom_config1); |
174 | if (ret < 0) |
175 | return ret; |
176 | |
177 | /* Modify FIR on parts which have configurable FIR filter */ |
178 | if (chip_info->fir_config_mask) { |
179 | ret &= ~chip_info->fir_config_mask; |
180 | ret |= field_prep(chip_info->fir_config_mask, MLX90614_CONST_FIR); |
181 | } |
182 | |
183 | ret &= ~chip_info->iir_config_mask; |
184 | ret |= field_prep(chip_info->iir_config_mask, i); |
185 | |
186 | /* Write changed values */ |
187 | ret = mlx90614_write_word(client, command: chip_info->op_eeprom_config1, value: ret); |
188 | return ret; |
189 | } |
190 | |
191 | #ifdef CONFIG_PM |
192 | /* |
193 | * If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since |
194 | * the last wake-up. This is normally only needed to get a valid temperature |
195 | * reading. EEPROM access does not need such delay. |
196 | * Return 0 on success, <0 on error. |
197 | */ |
198 | static int mlx90614_power_get(struct mlx90614_data *data, bool startup) |
199 | { |
200 | unsigned long now; |
201 | int ret; |
202 | |
203 | if (!data->wakeup_gpio) |
204 | return 0; |
205 | |
206 | ret = pm_runtime_resume_and_get(dev: &data->client->dev); |
207 | if (ret < 0) |
208 | return ret; |
209 | |
210 | if (startup) { |
211 | now = jiffies; |
212 | if (time_before(now, data->ready_timestamp) && |
213 | msleep_interruptible(msecs: jiffies_to_msecs( |
214 | j: data->ready_timestamp - now)) != 0) { |
215 | pm_runtime_put_autosuspend(dev: &data->client->dev); |
216 | return -EINTR; |
217 | } |
218 | } |
219 | |
220 | return 0; |
221 | } |
222 | |
223 | static void mlx90614_power_put(struct mlx90614_data *data) |
224 | { |
225 | if (!data->wakeup_gpio) |
226 | return; |
227 | |
228 | pm_runtime_mark_last_busy(dev: &data->client->dev); |
229 | pm_runtime_put_autosuspend(dev: &data->client->dev); |
230 | } |
231 | #else |
232 | static inline int mlx90614_power_get(struct mlx90614_data *data, bool startup) |
233 | { |
234 | return 0; |
235 | } |
236 | |
237 | static inline void mlx90614_power_put(struct mlx90614_data *data) |
238 | { |
239 | } |
240 | #endif |
241 | |
242 | static int mlx90614_read_raw(struct iio_dev *indio_dev, |
243 | struct iio_chan_spec const *channel, int *val, |
244 | int *val2, long mask) |
245 | { |
246 | struct mlx90614_data *data = iio_priv(indio_dev); |
247 | const struct mlx_chip_info *chip_info = data->chip_info; |
248 | u8 cmd, idx; |
249 | s32 ret; |
250 | |
251 | switch (mask) { |
252 | case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */ |
253 | switch (channel->channel2) { |
254 | case IIO_MOD_TEMP_AMBIENT: |
255 | cmd = chip_info->op_ram_ta; |
256 | break; |
257 | case IIO_MOD_TEMP_OBJECT: |
258 | if (chip_info->dual_channel && channel->channel) |
259 | return -EINVAL; |
260 | |
261 | switch (channel->channel) { |
262 | case 0: |
263 | cmd = chip_info->op_ram_tobj1; |
264 | break; |
265 | case 1: |
266 | cmd = chip_info->op_ram_tobj2; |
267 | break; |
268 | default: |
269 | return -EINVAL; |
270 | } |
271 | break; |
272 | default: |
273 | return -EINVAL; |
274 | } |
275 | |
276 | ret = mlx90614_power_get(data, startup: true); |
277 | if (ret < 0) |
278 | return ret; |
279 | ret = i2c_smbus_read_word_data(client: data->client, command: cmd); |
280 | mlx90614_power_put(data); |
281 | |
282 | if (ret < 0) |
283 | return ret; |
284 | |
285 | /* MSB is an error flag */ |
286 | if (ret & 0x8000) |
287 | return -EIO; |
288 | |
289 | *val = ret; |
290 | return IIO_VAL_INT; |
291 | case IIO_CHAN_INFO_OFFSET: |
292 | *val = MLX90614_CONST_OFFSET_DEC; |
293 | *val2 = MLX90614_CONST_OFFSET_REM; |
294 | return IIO_VAL_INT_PLUS_MICRO; |
295 | case IIO_CHAN_INFO_SCALE: |
296 | *val = MLX90614_CONST_SCALE; |
297 | return IIO_VAL_INT; |
298 | case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */ |
299 | ret = mlx90614_power_get(data, startup: false); |
300 | if (ret < 0) |
301 | return ret; |
302 | |
303 | mutex_lock(&data->lock); |
304 | ret = i2c_smbus_read_word_data(client: data->client, |
305 | command: chip_info->op_eeprom_emissivity); |
306 | mutex_unlock(lock: &data->lock); |
307 | mlx90614_power_put(data); |
308 | |
309 | if (ret < 0) |
310 | return ret; |
311 | |
312 | if (ret == chip_info->emissivity_max) { |
313 | *val = 1; |
314 | *val2 = 0; |
315 | } else { |
316 | *val = 0; |
317 | *val2 = ret * NSEC_PER_SEC / chip_info->emissivity_max; |
318 | } |
319 | return IIO_VAL_INT_PLUS_NANO; |
320 | /* IIR setting with FIR=1024 (MLX90614) or FIR=65536 (MLX90615) */ |
321 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
322 | ret = mlx90614_power_get(data, startup: false); |
323 | if (ret < 0) |
324 | return ret; |
325 | |
326 | mutex_lock(&data->lock); |
327 | ret = i2c_smbus_read_word_data(client: data->client, |
328 | command: chip_info->op_eeprom_config1); |
329 | mutex_unlock(lock: &data->lock); |
330 | mlx90614_power_put(data); |
331 | |
332 | if (ret < 0) |
333 | return ret; |
334 | |
335 | idx = field_get(chip_info->iir_config_mask, ret) - |
336 | chip_info->iir_valid_offset; |
337 | |
338 | *val = chip_info->iir_values[idx] / 100; |
339 | *val2 = (chip_info->iir_values[idx] % 100) * 10000; |
340 | return IIO_VAL_INT_PLUS_MICRO; |
341 | default: |
342 | return -EINVAL; |
343 | } |
344 | } |
345 | |
346 | static int mlx90614_write_raw(struct iio_dev *indio_dev, |
347 | struct iio_chan_spec const *channel, int val, |
348 | int val2, long mask) |
349 | { |
350 | struct mlx90614_data *data = iio_priv(indio_dev); |
351 | const struct mlx_chip_info *chip_info = data->chip_info; |
352 | s32 ret; |
353 | |
354 | switch (mask) { |
355 | case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/emissivity_max / LSB */ |
356 | if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0)) |
357 | return -EINVAL; |
358 | val = val * chip_info->emissivity_max + |
359 | val2 * chip_info->emissivity_max / NSEC_PER_SEC; |
360 | |
361 | ret = mlx90614_power_get(data, startup: false); |
362 | if (ret < 0) |
363 | return ret; |
364 | |
365 | mutex_lock(&data->lock); |
366 | ret = mlx90614_write_word(client: data->client, |
367 | command: chip_info->op_eeprom_emissivity, value: val); |
368 | mutex_unlock(lock: &data->lock); |
369 | mlx90614_power_put(data); |
370 | |
371 | return ret; |
372 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR Filter setting */ |
373 | if (val < 0 || val2 < 0) |
374 | return -EINVAL; |
375 | |
376 | ret = mlx90614_power_get(data, startup: false); |
377 | if (ret < 0) |
378 | return ret; |
379 | |
380 | mutex_lock(&data->lock); |
381 | ret = mlx90614_iir_search(client: data->client, |
382 | value: val * 100 + val2 / 10000); |
383 | mutex_unlock(lock: &data->lock); |
384 | mlx90614_power_put(data); |
385 | |
386 | return ret; |
387 | default: |
388 | return -EINVAL; |
389 | } |
390 | } |
391 | |
392 | static int mlx90614_write_raw_get_fmt(struct iio_dev *indio_dev, |
393 | struct iio_chan_spec const *channel, |
394 | long mask) |
395 | { |
396 | switch (mask) { |
397 | case IIO_CHAN_INFO_CALIBEMISSIVITY: |
398 | return IIO_VAL_INT_PLUS_NANO; |
399 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
400 | return IIO_VAL_INT_PLUS_MICRO; |
401 | default: |
402 | return -EINVAL; |
403 | } |
404 | } |
405 | |
406 | static int mlx90614_read_avail(struct iio_dev *indio_dev, |
407 | struct iio_chan_spec const *chan, |
408 | const int **vals, int *type, int *length, |
409 | long mask) |
410 | { |
411 | struct mlx90614_data *data = iio_priv(indio_dev); |
412 | const struct mlx_chip_info *chip_info = data->chip_info; |
413 | |
414 | switch (mask) { |
415 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: |
416 | *vals = (int *)chip_info->iir_freqs; |
417 | *type = IIO_VAL_INT_PLUS_MICRO; |
418 | *length = 2 * (ARRAY_SIZE(chip_info->iir_freqs) - |
419 | chip_info->iir_valid_offset); |
420 | return IIO_AVAIL_LIST; |
421 | default: |
422 | return -EINVAL; |
423 | } |
424 | } |
425 | |
426 | static const struct iio_chan_spec mlx90614_channels[] = { |
427 | { |
428 | .type = IIO_TEMP, |
429 | .modified = 1, |
430 | .channel2 = IIO_MOD_TEMP_AMBIENT, |
431 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
432 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | |
433 | BIT(IIO_CHAN_INFO_SCALE), |
434 | }, |
435 | { |
436 | .type = IIO_TEMP, |
437 | .modified = 1, |
438 | .channel2 = IIO_MOD_TEMP_OBJECT, |
439 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
440 | BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | |
441 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
442 | .info_mask_separate_available = |
443 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
444 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | |
445 | BIT(IIO_CHAN_INFO_SCALE), |
446 | }, |
447 | { |
448 | .type = IIO_TEMP, |
449 | .indexed = 1, |
450 | .modified = 1, |
451 | .channel = 1, |
452 | .channel2 = IIO_MOD_TEMP_OBJECT, |
453 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
454 | BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) | |
455 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
456 | .info_mask_separate_available = |
457 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), |
458 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | |
459 | BIT(IIO_CHAN_INFO_SCALE), |
460 | }, |
461 | }; |
462 | |
463 | static const struct iio_info mlx90614_info = { |
464 | .read_raw = mlx90614_read_raw, |
465 | .write_raw = mlx90614_write_raw, |
466 | .write_raw_get_fmt = mlx90614_write_raw_get_fmt, |
467 | .read_avail = mlx90614_read_avail, |
468 | }; |
469 | |
470 | #ifdef CONFIG_PM |
471 | static int mlx90614_sleep(struct mlx90614_data *data) |
472 | { |
473 | const struct mlx_chip_info *chip_info = data->chip_info; |
474 | s32 ret; |
475 | |
476 | if (!data->wakeup_gpio) { |
477 | dev_dbg(&data->client->dev, "Sleep disabled" ); |
478 | return -ENOSYS; |
479 | } |
480 | |
481 | dev_dbg(&data->client->dev, "Requesting sleep" ); |
482 | |
483 | mutex_lock(&data->lock); |
484 | ret = i2c_smbus_xfer(adapter: data->client->adapter, addr: data->client->addr, |
485 | flags: data->client->flags | I2C_CLIENT_PEC, |
486 | I2C_SMBUS_WRITE, command: chip_info->op_sleep, |
487 | I2C_SMBUS_BYTE, NULL); |
488 | mutex_unlock(lock: &data->lock); |
489 | |
490 | return ret; |
491 | } |
492 | |
493 | static int mlx90614_wakeup(struct mlx90614_data *data) |
494 | { |
495 | const struct mlx_chip_info *chip_info = data->chip_info; |
496 | |
497 | if (!data->wakeup_gpio) { |
498 | dev_dbg(&data->client->dev, "Wake-up disabled" ); |
499 | return -ENOSYS; |
500 | } |
501 | |
502 | dev_dbg(&data->client->dev, "Requesting wake-up" ); |
503 | |
504 | i2c_lock_bus(adapter: data->client->adapter, I2C_LOCK_ROOT_ADAPTER); |
505 | gpiod_direction_output(desc: data->wakeup_gpio, value: 0); |
506 | msleep(msecs: chip_info->wakeup_delay_ms); |
507 | gpiod_direction_input(desc: data->wakeup_gpio); |
508 | i2c_unlock_bus(adapter: data->client->adapter, I2C_LOCK_ROOT_ADAPTER); |
509 | |
510 | data->ready_timestamp = jiffies + |
511 | msecs_to_jiffies(MLX90614_TIMING_STARTUP); |
512 | |
513 | /* |
514 | * Quirk: the i2c controller may get confused right after the |
515 | * wake-up signal has been sent. As a workaround, do a dummy read. |
516 | * If the read fails, the controller will probably be reset so that |
517 | * further reads will work. |
518 | */ |
519 | i2c_smbus_read_word_data(client: data->client, command: chip_info->op_eeprom_config1); |
520 | |
521 | return 0; |
522 | } |
523 | |
524 | /* Return wake-up GPIO or NULL if sleep functionality should be disabled. */ |
525 | static struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client) |
526 | { |
527 | struct gpio_desc *gpio; |
528 | |
529 | if (!i2c_check_functionality(adap: client->adapter, |
530 | I2C_FUNC_SMBUS_WRITE_BYTE)) { |
531 | dev_info(&client->dev, |
532 | "i2c adapter does not support SMBUS_WRITE_BYTE, sleep disabled" ); |
533 | return NULL; |
534 | } |
535 | |
536 | gpio = devm_gpiod_get_optional(dev: &client->dev, con_id: "wakeup" , flags: GPIOD_IN); |
537 | |
538 | if (IS_ERR(ptr: gpio)) { |
539 | dev_warn(&client->dev, |
540 | "gpio acquisition failed with error %ld, sleep disabled" , |
541 | PTR_ERR(gpio)); |
542 | return NULL; |
543 | } else if (!gpio) { |
544 | dev_info(&client->dev, |
545 | "wakeup-gpio not found, sleep disabled" ); |
546 | } |
547 | |
548 | return gpio; |
549 | } |
550 | #else |
551 | static inline int mlx90614_sleep(struct mlx90614_data *data) |
552 | { |
553 | return -ENOSYS; |
554 | } |
555 | static inline int mlx90614_wakeup(struct mlx90614_data *data) |
556 | { |
557 | return -ENOSYS; |
558 | } |
559 | static inline struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client) |
560 | { |
561 | return NULL; |
562 | } |
563 | #endif |
564 | |
565 | /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */ |
566 | static int mlx90614_probe_num_ir_sensors(struct i2c_client *client) |
567 | { |
568 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
569 | struct mlx90614_data *data = iio_priv(indio_dev); |
570 | const struct mlx_chip_info *chip_info = data->chip_info; |
571 | s32 ret; |
572 | |
573 | if (chip_info->dual_channel) |
574 | return 0; |
575 | |
576 | ret = i2c_smbus_read_word_data(client, command: chip_info->op_eeprom_config1); |
577 | |
578 | if (ret < 0) |
579 | return ret; |
580 | |
581 | return (ret & MLX90614_CONFIG_DUAL_MASK) ? 1 : 0; |
582 | } |
583 | |
584 | static int mlx90614_probe(struct i2c_client *client) |
585 | { |
586 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
587 | struct iio_dev *indio_dev; |
588 | struct mlx90614_data *data; |
589 | int ret; |
590 | |
591 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) |
592 | return -EOPNOTSUPP; |
593 | |
594 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data)); |
595 | if (!indio_dev) |
596 | return -ENOMEM; |
597 | |
598 | data = iio_priv(indio_dev); |
599 | i2c_set_clientdata(client, data: indio_dev); |
600 | data->client = client; |
601 | mutex_init(&data->lock); |
602 | data->wakeup_gpio = mlx90614_probe_wakeup(client); |
603 | data->chip_info = i2c_get_match_data(client); |
604 | |
605 | mlx90614_wakeup(data); |
606 | |
607 | indio_dev->name = id->name; |
608 | indio_dev->modes = INDIO_DIRECT_MODE; |
609 | indio_dev->info = &mlx90614_info; |
610 | |
611 | ret = mlx90614_probe_num_ir_sensors(client); |
612 | switch (ret) { |
613 | case 0: |
614 | dev_dbg(&client->dev, "Found single sensor" ); |
615 | indio_dev->channels = mlx90614_channels; |
616 | indio_dev->num_channels = 2; |
617 | break; |
618 | case 1: |
619 | dev_dbg(&client->dev, "Found dual sensor" ); |
620 | indio_dev->channels = mlx90614_channels; |
621 | indio_dev->num_channels = 3; |
622 | break; |
623 | default: |
624 | return ret; |
625 | } |
626 | |
627 | if (data->wakeup_gpio) { |
628 | pm_runtime_set_autosuspend_delay(dev: &client->dev, |
629 | MLX90614_AUTOSLEEP_DELAY); |
630 | pm_runtime_use_autosuspend(dev: &client->dev); |
631 | pm_runtime_set_active(dev: &client->dev); |
632 | pm_runtime_enable(dev: &client->dev); |
633 | } |
634 | |
635 | return iio_device_register(indio_dev); |
636 | } |
637 | |
638 | static void mlx90614_remove(struct i2c_client *client) |
639 | { |
640 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
641 | struct mlx90614_data *data = iio_priv(indio_dev); |
642 | |
643 | iio_device_unregister(indio_dev); |
644 | |
645 | if (data->wakeup_gpio) { |
646 | pm_runtime_disable(dev: &client->dev); |
647 | if (!pm_runtime_status_suspended(dev: &client->dev)) |
648 | mlx90614_sleep(data); |
649 | pm_runtime_set_suspended(dev: &client->dev); |
650 | } |
651 | } |
652 | |
653 | static const struct mlx_chip_info mlx90614_chip_info = { |
654 | .op_eeprom_emissivity = MLX90614_OP_EEPROM | 0x04, |
655 | .op_eeprom_config1 = MLX90614_OP_EEPROM | 0x05, |
656 | .op_ram_ta = MLX90614_OP_RAM | 0x06, |
657 | .op_ram_tobj1 = MLX90614_OP_RAM | 0x07, |
658 | .op_ram_tobj2 = MLX90614_OP_RAM | 0x08, |
659 | .op_sleep = MLX90614_OP_SLEEP, |
660 | .dual_channel = true, |
661 | .wakeup_delay_ms = MLX90614_TIMING_WAKEUP, |
662 | .emissivity_max = 65535, |
663 | .fir_config_mask = MLX90614_CONFIG_FIR_MASK, |
664 | .iir_config_mask = MLX90614_CONFIG_IIR_MASK, |
665 | .iir_valid_offset = 0, |
666 | .iir_values = { 77, 31, 20, 15, 723, 153, 110, 86 }, |
667 | .iir_freqs = { |
668 | { 0, 150000 }, /* 13% ~= 0.15 Hz */ |
669 | { 0, 200000 }, /* 17% ~= 0.20 Hz */ |
670 | { 0, 310000 }, /* 25% ~= 0.31 Hz */ |
671 | { 0, 770000 }, /* 50% ~= 0.77 Hz */ |
672 | { 0, 860000 }, /* 57% ~= 0.86 Hz */ |
673 | { 1, 100000 }, /* 67% ~= 1.10 Hz */ |
674 | { 1, 530000 }, /* 80% ~= 1.53 Hz */ |
675 | { 7, 230000 } /* 100% ~= 7.23 Hz */ |
676 | }, |
677 | }; |
678 | |
679 | static const struct mlx_chip_info mlx90615_chip_info = { |
680 | .op_eeprom_emissivity = MLX90615_OP_EEPROM | 0x03, |
681 | .op_eeprom_config1 = MLX90615_OP_EEPROM | 0x02, |
682 | .op_ram_ta = MLX90615_OP_RAM | 0x06, |
683 | .op_ram_tobj1 = MLX90615_OP_RAM | 0x07, |
684 | .op_ram_tobj2 = MLX90615_OP_RAM | 0x08, |
685 | .op_sleep = MLX90615_OP_SLEEP, |
686 | .dual_channel = false, |
687 | .wakeup_delay_ms = MLX90615_TIMING_WAKEUP, |
688 | .emissivity_max = 16383, |
689 | .fir_config_mask = 0, /* MLX90615 FIR is fixed */ |
690 | .iir_config_mask = MLX90615_CONFIG_IIR_MASK, |
691 | /* IIR value 0 is FORBIDDEN COMBINATION on MLX90615 */ |
692 | .iir_valid_offset = 1, |
693 | .iir_values = { 500, 50, 30, 20, 15, 13, 10 }, |
694 | .iir_freqs = { |
695 | { 0, 100000 }, /* 14% ~= 0.10 Hz */ |
696 | { 0, 130000 }, /* 17% ~= 0.13 Hz */ |
697 | { 0, 150000 }, /* 20% ~= 0.15 Hz */ |
698 | { 0, 200000 }, /* 25% ~= 0.20 Hz */ |
699 | { 0, 300000 }, /* 33% ~= 0.30 Hz */ |
700 | { 0, 500000 }, /* 50% ~= 0.50 Hz */ |
701 | { 5, 000000 }, /* 100% ~= 5.00 Hz */ |
702 | }, |
703 | }; |
704 | |
705 | static const struct i2c_device_id mlx90614_id[] = { |
706 | { "mlx90614" , .driver_data = (kernel_ulong_t)&mlx90614_chip_info }, |
707 | { "mlx90615" , .driver_data = (kernel_ulong_t)&mlx90615_chip_info }, |
708 | { } |
709 | }; |
710 | MODULE_DEVICE_TABLE(i2c, mlx90614_id); |
711 | |
712 | static const struct of_device_id mlx90614_of_match[] = { |
713 | { .compatible = "melexis,mlx90614" , .data = &mlx90614_chip_info }, |
714 | { .compatible = "melexis,mlx90615" , .data = &mlx90615_chip_info }, |
715 | { } |
716 | }; |
717 | MODULE_DEVICE_TABLE(of, mlx90614_of_match); |
718 | |
719 | static int mlx90614_pm_suspend(struct device *dev) |
720 | { |
721 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
722 | struct mlx90614_data *data = iio_priv(indio_dev); |
723 | |
724 | if (data->wakeup_gpio && pm_runtime_active(dev)) |
725 | return mlx90614_sleep(data); |
726 | |
727 | return 0; |
728 | } |
729 | |
730 | static int mlx90614_pm_resume(struct device *dev) |
731 | { |
732 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
733 | struct mlx90614_data *data = iio_priv(indio_dev); |
734 | int err; |
735 | |
736 | if (data->wakeup_gpio) { |
737 | err = mlx90614_wakeup(data); |
738 | if (err < 0) |
739 | return err; |
740 | |
741 | pm_runtime_disable(dev); |
742 | pm_runtime_set_active(dev); |
743 | pm_runtime_enable(dev); |
744 | } |
745 | |
746 | return 0; |
747 | } |
748 | |
749 | static int mlx90614_pm_runtime_suspend(struct device *dev) |
750 | { |
751 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
752 | struct mlx90614_data *data = iio_priv(indio_dev); |
753 | |
754 | return mlx90614_sleep(data); |
755 | } |
756 | |
757 | static int mlx90614_pm_runtime_resume(struct device *dev) |
758 | { |
759 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
760 | struct mlx90614_data *data = iio_priv(indio_dev); |
761 | |
762 | return mlx90614_wakeup(data); |
763 | } |
764 | |
765 | static const struct dev_pm_ops mlx90614_pm_ops = { |
766 | SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume) |
767 | RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend, |
768 | mlx90614_pm_runtime_resume, NULL) |
769 | }; |
770 | |
771 | static struct i2c_driver mlx90614_driver = { |
772 | .driver = { |
773 | .name = "mlx90614" , |
774 | .of_match_table = mlx90614_of_match, |
775 | .pm = pm_ptr(&mlx90614_pm_ops), |
776 | }, |
777 | .probe = mlx90614_probe, |
778 | .remove = mlx90614_remove, |
779 | .id_table = mlx90614_id, |
780 | }; |
781 | module_i2c_driver(mlx90614_driver); |
782 | |
783 | MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>" ); |
784 | MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>" ); |
785 | MODULE_AUTHOR("Crt Mori <cmo@melexis.com>" ); |
786 | MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver" ); |
787 | MODULE_LICENSE("GPL" ); |
788 | |