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