Commit | Line | Data |
---|---|---|
474fe212 PM |
1 | /* |
2 | * mlx90614.c - Support for Melexis MLX90614 contactless IR temperature sensor | |
3 | * | |
4 | * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> | |
5 | * | |
6 | * This file is subject to the terms and conditions of version 2 of | |
7 | * the GNU General Public License. See the file COPYING in the main | |
8 | * directory of this archive for more details. | |
9 | * | |
10 | * Driver for the Melexis MLX90614 I2C 16-bit IR thermopile sensor | |
11 | * | |
12 | * (7-bit I2C slave address 0x5a, 100KHz bus speed only!) | |
13 | * | |
14 | * TODO: sleep mode, configuration EEPROM | |
15 | */ | |
16 | ||
17 | #include <linux/err.h> | |
18 | #include <linux/i2c.h> | |
19 | #include <linux/module.h> | |
20 | ||
21 | #include <linux/iio/iio.h> | |
22 | ||
23 | #define MLX90614_OP_RAM 0x00 | |
24 | ||
25 | /* RAM offsets with 16-bit data, MSB first */ | |
c7586584 VCSM |
26 | #define MLX90614_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */ |
27 | #define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */ | |
474fe212 PM |
28 | |
29 | struct mlx90614_data { | |
30 | struct i2c_client *client; | |
31 | }; | |
32 | ||
33 | static int mlx90614_read_raw(struct iio_dev *indio_dev, | |
34 | struct iio_chan_spec const *channel, int *val, | |
35 | int *val2, long mask) | |
36 | { | |
37 | struct mlx90614_data *data = iio_priv(indio_dev); | |
38 | s32 ret; | |
39 | ||
40 | switch (mask) { | |
41 | case IIO_CHAN_INFO_RAW: /* 0.02K / LSB */ | |
42 | switch (channel->channel2) { | |
43 | case IIO_MOD_TEMP_AMBIENT: | |
44 | ret = i2c_smbus_read_word_data(data->client, | |
c7586584 | 45 | MLX90614_TA); |
474fe212 PM |
46 | if (ret < 0) |
47 | return ret; | |
48 | break; | |
49 | case IIO_MOD_TEMP_OBJECT: | |
50 | ret = i2c_smbus_read_word_data(data->client, | |
c7586584 | 51 | MLX90614_TOBJ1); |
474fe212 PM |
52 | if (ret < 0) |
53 | return ret; | |
54 | break; | |
55 | default: | |
56 | return -EINVAL; | |
57 | } | |
58 | *val = ret; | |
59 | return IIO_VAL_INT; | |
60 | case IIO_CHAN_INFO_OFFSET: | |
61 | *val = 13657; | |
62 | *val2 = 500000; | |
63 | return IIO_VAL_INT_PLUS_MICRO; | |
64 | case IIO_CHAN_INFO_SCALE: | |
65 | *val = 20; | |
66 | return IIO_VAL_INT; | |
67 | default: | |
68 | return -EINVAL; | |
69 | } | |
70 | } | |
71 | ||
72 | static const struct iio_chan_spec mlx90614_channels[] = { | |
73 | { | |
74 | .type = IIO_TEMP, | |
75 | .modified = 1, | |
76 | .channel2 = IIO_MOD_TEMP_AMBIENT, | |
77 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
78 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | | |
79 | BIT(IIO_CHAN_INFO_SCALE), | |
80 | }, | |
81 | { | |
82 | .type = IIO_TEMP, | |
83 | .modified = 1, | |
84 | .channel2 = IIO_MOD_TEMP_OBJECT, | |
85 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | |
86 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | | |
87 | BIT(IIO_CHAN_INFO_SCALE), | |
88 | }, | |
89 | }; | |
90 | ||
91 | static const struct iio_info mlx90614_info = { | |
92 | .read_raw = mlx90614_read_raw, | |
93 | .driver_module = THIS_MODULE, | |
94 | }; | |
95 | ||
96 | static int mlx90614_probe(struct i2c_client *client, | |
97 | const struct i2c_device_id *id) | |
98 | { | |
99 | struct iio_dev *indio_dev; | |
100 | struct mlx90614_data *data; | |
101 | ||
102 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) | |
103 | return -ENODEV; | |
104 | ||
105 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
106 | if (!indio_dev) | |
107 | return -ENOMEM; | |
108 | ||
109 | data = iio_priv(indio_dev); | |
110 | i2c_set_clientdata(client, indio_dev); | |
111 | data->client = client; | |
112 | ||
113 | indio_dev->dev.parent = &client->dev; | |
114 | indio_dev->name = id->name; | |
115 | indio_dev->modes = INDIO_DIRECT_MODE; | |
116 | indio_dev->info = &mlx90614_info; | |
117 | ||
118 | indio_dev->channels = mlx90614_channels; | |
119 | indio_dev->num_channels = ARRAY_SIZE(mlx90614_channels); | |
120 | ||
121 | return iio_device_register(indio_dev); | |
122 | } | |
123 | ||
124 | static int mlx90614_remove(struct i2c_client *client) | |
125 | { | |
126 | iio_device_unregister(i2c_get_clientdata(client)); | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | static const struct i2c_device_id mlx90614_id[] = { | |
132 | { "mlx90614", 0 }, | |
133 | { } | |
134 | }; | |
135 | MODULE_DEVICE_TABLE(i2c, mlx90614_id); | |
136 | ||
137 | static struct i2c_driver mlx90614_driver = { | |
138 | .driver = { | |
139 | .name = "mlx90614", | |
140 | .owner = THIS_MODULE, | |
141 | }, | |
142 | .probe = mlx90614_probe, | |
143 | .remove = mlx90614_remove, | |
144 | .id_table = mlx90614_id, | |
145 | }; | |
146 | module_i2c_driver(mlx90614_driver); | |
147 | ||
148 | MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); | |
149 | MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver"); | |
150 | MODULE_LICENSE("GPL"); |