summaryrefslogtreecommitdiff
path: root/drivers/iio/temperature/mlx90614.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-14 03:37:33 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-14 03:37:33 +0300
commitb79013b2449c23f1f505bdf39c5a6c330338b244 (patch)
tree67908ffb1705a595cda8de7224d121fa40b8f36d /drivers/iio/temperature/mlx90614.c
parentc4be50eee2bd4d50e0f0ca58776f685c08de69c3 (diff)
parentc610f7f772aa06ae2bd8e5ace87cde4d90f70198 (diff)
downloadlinux-b79013b2449c23f1f505bdf39c5a6c330338b244.tar.xz
Merge tag 'staging-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging driver updates from Greg KH: "Here's the big staging driver patchset for 4.1-rc1. There's a lot of patches here, the Outreachy application period happened during this development cycle, so that means that there was a lot of cleanup patches accepted. Other than the normal coding style and sparse fixes here, there are some driver updates and work toward making some of the drivers into "mergable" shape (like the Unisys drivers.) All of these have been in linux-next for a while" * tag 'staging-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1214 commits) staging: lustre: orthography & coding style staging: lustre: lnet: lnet: fix error return code staging: lustre: fix sparse warning Revert "Staging: sm750fb: Fix C99 Comments" Staging: rtl8192u: use correct array for debug output staging: rtl8192e: Remove dead code staging: rtl8192e: Comment cleanup (style/format) staging: rtl8192e: Fix indentation in rtllib_rx_auth_resp() staging: rtl8192e: Decrease nesting of rtllib_rx_auth_resp() staging: rtl8192e: Divide rtllib_rx_auth() staging: rtl8192e: Fix PRINTK_WITHOUT_KERN_LEVEL warnings staging: rtl8192e: Fix DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON warning staging: rtl8192e: Fix BRACES warning staging: rtl8192e: Fix LINE_CONTINUATIONS warning staging: rtl8192e: Fix UNNECESSARY_PARENTHESES warnings staging: rtl8192e: remove unused EXPORT_SYMBOL_RSL macro staging: rtl8192e: Fix RETURN_VOID warnings staging: rtl8192e: Fix UNNECESSARY_ELSE warning staging: rtl8723au: Remove unneeded comments staging: rtl8723au: Use __func__ in trace logs ...
Diffstat (limited to 'drivers/iio/temperature/mlx90614.c')
-rw-r--r--drivers/iio/temperature/mlx90614.c97
1 files changed, 84 insertions, 13 deletions
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index c8b6ac8b2d69..a112fc9abf43 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -2,6 +2,7 @@
* mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor
*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
+ * Copyright (c) 2015 Essensium NV
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
@@ -20,11 +21,35 @@
#include <linux/iio/iio.h>
-#define MLX90614_OP_RAM 0x00
+#define MLX90614_OP_RAM 0x00
+#define MLX90614_OP_EEPROM 0x20
+#define MLX90614_OP_SLEEP 0xff
/* RAM offsets with 16-bit data, MSB first */
-#define MLX90614_TA 0x06 /* ambient temperature */
-#define MLX90614_TOBJ1 0x07 /* object temperature */
+#define MLX90614_RAW1 (MLX90614_OP_RAM | 0x04) /* raw data IR channel 1 */
+#define MLX90614_RAW2 (MLX90614_OP_RAM | 0x05) /* raw data IR channel 2 */
+#define MLX90614_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */
+#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */
+#define MLX90614_TOBJ2 (MLX90614_OP_RAM | 0x08) /* object 2 temperature */
+
+/* EEPROM offsets with 16-bit data, MSB first */
+#define MLX90614_EMISSIVITY (MLX90614_OP_EEPROM | 0x04) /* emissivity correction coefficient */
+#define MLX90614_CONFIG (MLX90614_OP_EEPROM | 0x05) /* configuration register */
+
+/* Control bits in configuration register */
+#define MLX90614_CONFIG_IIR_SHIFT 0 /* IIR coefficient */
+#define MLX90614_CONFIG_IIR_MASK (0x7 << MLX90614_CONFIG_IIR_SHIFT)
+#define MLX90614_CONFIG_DUAL_SHIFT 6 /* single (0) or dual (1) IR sensor */
+#define MLX90614_CONFIG_DUAL_MASK (1 << MLX90614_CONFIG_DUAL_SHIFT)
+#define MLX90614_CONFIG_FIR_SHIFT 8 /* FIR coefficient */
+#define MLX90614_CONFIG_FIR_MASK (0x7 << MLX90614_CONFIG_FIR_SHIFT)
+#define MLX90614_CONFIG_GAIN_SHIFT 11 /* gain */
+#define MLX90614_CONFIG_GAIN_MASK (0x7 << MLX90614_CONFIG_GAIN_SHIFT)
+
+/* Timings (in ms) */
+#define MLX90614_TIMING_EEPROM 20 /* time for EEPROM write/erase to complete */
+#define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */
+#define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */
struct mlx90614_data {
struct i2c_client *client;
@@ -35,26 +60,34 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct mlx90614_data *data = iio_priv(indio_dev);
+ u8 cmd;
s32 ret;
switch (mask) {
case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */
switch (channel->channel2) {
case IIO_MOD_TEMP_AMBIENT:
- ret = i2c_smbus_read_word_data(data->client,
- MLX90614_OP_RAM | MLX90614_TA);
- if (ret < 0)
- return ret;
+ cmd = MLX90614_TA;
break;
case IIO_MOD_TEMP_OBJECT:
- ret = i2c_smbus_read_word_data(data->client,
- MLX90614_OP_RAM | MLX90614_TOBJ1);
- if (ret < 0)
- return ret;
+ switch (channel->channel) {
+ case 0:
+ cmd = MLX90614_TOBJ1;
+ break;
+ case 1:
+ cmd = MLX90614_TOBJ2;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
}
+
+ ret = i2c_smbus_read_word_data(data->client, cmd);
+ if (ret < 0)
+ return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
@@ -86,6 +119,16 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .modified = 1,
+ .channel = 1,
+ .channel2 = IIO_MOD_TEMP_OBJECT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
};
static const struct iio_info mlx90614_info = {
@@ -93,11 +136,25 @@ static const struct iio_info mlx90614_info = {
.driver_module = THIS_MODULE,
};
+/* Return 0 for single sensor, 1 for dual sensor, <0 on error. */
+static int mlx90614_probe_num_ir_sensors(struct i2c_client *client)
+{
+ s32 ret;
+
+ ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
+
+ if (ret < 0)
+ return ret;
+
+ return (ret & MLX90614_CONFIG_DUAL_MASK) ? 1 : 0;
+}
+
static int mlx90614_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct mlx90614_data *data;
+ int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
@@ -115,8 +172,21 @@ static int mlx90614_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mlx90614_info;
- indio_dev->channels = mlx90614_channels;
- indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels);
+ ret = mlx90614_probe_num_ir_sensors(client);
+ switch (ret) {
+ case 0:
+ dev_dbg(&client->dev, "Found single sensor");
+ indio_dev->channels = mlx90614_channels;
+ indio_dev->num_channels = 2;
+ break;
+ case 1:
+ dev_dbg(&client->dev, "Found dual sensor");
+ indio_dev->channels = mlx90614_channels;
+ indio_dev->num_channels = 3;
+ break;
+ default:
+ return ret;
+ }
return iio_device_register(indio_dev);
}
@@ -146,5 +216,6 @@ static struct i2c_driver mlx90614_driver = {
module_i2c_driver(mlx90614_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
+MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
MODULE_LICENSE("GPL");