Merge branch 'address-masking'
[linux-2.6-microblaze.git] / drivers / iio / humidity / si7020.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors
4  * Copyright (c) 2013,2014  Uplogix, Inc.
5  * David Barksdale <dbarksdale@uplogix.com>
6  */
7
8 /*
9  * The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors
10  * are i2c devices which have an identical programming interface for
11  * measuring relative humidity and temperature. The Si7013 has an additional
12  * temperature input which this driver does not support.
13  *
14  * Data Sheets:
15  *   Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
16  *   Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
17  *   Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
18  */
19
20 #include <linux/delay.h>
21 #include <linux/i2c.h>
22 #include <linux/module.h>
23 #include <linux/mod_devicetable.h>
24 #include <linux/slab.h>
25 #include <linux/sysfs.h>
26 #include <linux/stat.h>
27
28 #include <linux/iio/iio.h>
29 #include <linux/iio/sysfs.h>
30
31 /* Measure Relative Humidity, Hold Master Mode */
32 #define SI7020CMD_RH_HOLD       0xE5
33 /* Measure Temperature, Hold Master Mode */
34 #define SI7020CMD_TEMP_HOLD     0xE3
35 /* Software Reset */
36 #define SI7020CMD_RESET         0xFE
37 #define SI7020CMD_USR_WRITE     0xE6
38 /* "Heater Enabled" bit in the User Register */
39 #define SI7020_USR_HEATER_EN    BIT(2)
40 #define SI7020CMD_HEATER_WRITE  0x51
41 /* Heater current configuration bits */
42 #define SI7020_HEATER_VAL       GENMASK(3, 0)
43
44 struct si7020_data {
45         struct i2c_client *client;
46         /* Lock for cached register values */
47         struct mutex lock;
48         u8 user_reg;
49         u8 heater_reg;
50 };
51
52 static const int si7020_heater_vals[] = { 0, 1, 0xF };
53
54 static int si7020_read_raw(struct iio_dev *indio_dev,
55                            struct iio_chan_spec const *chan, int *val,
56                            int *val2, long mask)
57 {
58         struct si7020_data *data = iio_priv(indio_dev);
59         int ret;
60
61         switch (mask) {
62         case IIO_CHAN_INFO_RAW:
63                 if (chan->type == IIO_CURRENT) {
64                         *val = data->heater_reg;
65                         return IIO_VAL_INT;
66                 }
67
68                 ret = i2c_smbus_read_word_swapped(data->client,
69                                                   chan->type == IIO_TEMP ?
70                                                   SI7020CMD_TEMP_HOLD :
71                                                   SI7020CMD_RH_HOLD);
72                 if (ret < 0)
73                         return ret;
74                 *val = ret >> 2;
75                 /*
76                  * Humidity values can slightly exceed the 0-100%RH
77                  * range and should be corrected by software
78                  */
79                 if (chan->type == IIO_HUMIDITYRELATIVE)
80                         *val = clamp_val(*val, 786, 13893);
81                 return IIO_VAL_INT;
82         case IIO_CHAN_INFO_SCALE:
83                 if (chan->type == IIO_TEMP)
84                         *val = 175720; /* = 175.72 * 1000 */
85                 else
86                         *val = 125 * 1000;
87                 *val2 = 65536 >> 2;
88                 return IIO_VAL_FRACTIONAL;
89         case IIO_CHAN_INFO_OFFSET:
90                 /*
91                  * Since iio_convert_raw_to_processed_unlocked assumes offset
92                  * is an integer we have to round these values and lose
93                  * accuracy.
94                  * Relative humidity will be 0.0032959% too high and
95                  * temperature will be 0.00277344 degrees too high.
96                  * This is no big deal because it's within the accuracy of the
97                  * sensor.
98                  */
99                 if (chan->type == IIO_TEMP)
100                         *val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */
101                 else
102                         *val = -786; /* = -6 * (65536 >> 2) / 125 */
103                 return IIO_VAL_INT;
104         default:
105                 break;
106         }
107
108         return -EINVAL;
109 }
110
111 static const struct iio_chan_spec si7020_channels[] = {
112         {
113                 .type = IIO_HUMIDITYRELATIVE,
114                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
115                         BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
116         },
117         {
118                 .type = IIO_TEMP,
119                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
120                         BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
121         },
122         {
123                 .type = IIO_CURRENT,
124                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
125                 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
126                 .extend_name = "heater",
127         }
128 };
129
130 static int si7020_update_reg(struct si7020_data *data,
131                                 u8 *reg, u8 cmd, u8 mask, u8 val)
132 {
133         u8 new = (*reg & ~mask) | val;
134         int ret;
135
136         ret = i2c_smbus_write_byte_data(data->client, cmd, new);
137         if (ret)
138                 return ret;
139
140         *reg = new;
141
142         return 0;
143 }
144
145 static int si7020_write_raw(struct iio_dev *indio_dev,
146                              struct iio_chan_spec const *chan,
147                              int val, int val2, long mask)
148 {
149         struct si7020_data *data = iio_priv(indio_dev);
150         int ret;
151
152         switch (mask) {
153         case IIO_CHAN_INFO_RAW:
154                 if (chan->type != IIO_CURRENT || val2 != 0 ||
155                         val < si7020_heater_vals[0] || val > si7020_heater_vals[2])
156                         return -EINVAL;
157
158                 scoped_guard(mutex, &data->lock)
159                         ret = si7020_update_reg(data, &data->heater_reg,
160                                         SI7020CMD_HEATER_WRITE, SI7020_HEATER_VAL, val);
161                 return ret;
162         default:
163                 return -EINVAL;
164         }
165 }
166
167 static int si7020_read_available(struct iio_dev *indio_dev,
168                                   struct iio_chan_spec const *chan,
169                                   const int **vals,
170                                   int *type, int *length, long mask)
171 {
172         if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT)
173                 return -EINVAL;
174
175         *vals = si7020_heater_vals;
176         *type = IIO_VAL_INT;
177
178         return IIO_AVAIL_RANGE;
179 }
180
181 static ssize_t si7020_show_heater_en(struct device *dev,
182                                  struct device_attribute *attr, char *buf)
183 {
184         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
185         struct si7020_data *data = iio_priv(indio_dev);
186
187         return sysfs_emit(buf, "%d\n", !!(data->user_reg & SI7020_USR_HEATER_EN));
188 }
189
190 static ssize_t si7020_store_heater_en(struct device *dev,
191                                   struct device_attribute *attr,
192                                   const char *buf, size_t len)
193 {
194         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
195         struct si7020_data *data = iio_priv(indio_dev);
196         int ret;
197         bool val;
198
199         ret = kstrtobool(buf, &val);
200         if (ret)
201                 return ret;
202
203         scoped_guard(mutex, &data->lock)
204                 ret = si7020_update_reg(data, &data->user_reg, SI7020CMD_USR_WRITE,
205                                 SI7020_USR_HEATER_EN, val ? SI7020_USR_HEATER_EN : 0);
206
207         return ret < 0 ? ret : len;
208 }
209
210 static IIO_DEVICE_ATTR(heater_enable, 0644,
211                        si7020_show_heater_en, si7020_store_heater_en, 0);
212
213 static struct attribute *si7020_attributes[] = {
214         &iio_dev_attr_heater_enable.dev_attr.attr,
215         NULL
216 };
217
218 static const struct attribute_group si7020_attribute_group = {
219         .attrs = si7020_attributes,
220 };
221
222 static const struct iio_info si7020_info = {
223         .read_raw = si7020_read_raw,
224         .write_raw = si7020_write_raw,
225         .read_avail = si7020_read_available,
226         .attrs = &si7020_attribute_group,
227 };
228
229 static int si7020_probe(struct i2c_client *client)
230 {
231         struct iio_dev *indio_dev;
232         struct si7020_data *data;
233         int ret;
234
235         if (!i2c_check_functionality(client->adapter,
236                                      I2C_FUNC_SMBUS_WRITE_BYTE |
237                                      I2C_FUNC_SMBUS_READ_WORD_DATA))
238                 return -EOPNOTSUPP;
239
240         /* Reset device, loads default settings. */
241         ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
242         if (ret < 0)
243                 return ret;
244         /* Wait the maximum power-up time after software reset. */
245         msleep(15);
246
247         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
248         if (!indio_dev)
249                 return -ENOMEM;
250
251         data = iio_priv(indio_dev);
252         i2c_set_clientdata(client, indio_dev);
253         data->client = client;
254         mutex_init(&data->lock);
255
256         indio_dev->name = dev_name(&client->dev);
257         indio_dev->modes = INDIO_DIRECT_MODE;
258         indio_dev->info = &si7020_info;
259         indio_dev->channels = si7020_channels;
260         indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
261
262         /* All the "reserved" bits in the User Register are 1s by default */
263         data->user_reg = 0x3A;
264         data->heater_reg = 0x0;
265
266         return devm_iio_device_register(&client->dev, indio_dev);
267 }
268
269 static const struct i2c_device_id si7020_id[] = {
270         { "si7020" },
271         { "th06" },
272         { }
273 };
274 MODULE_DEVICE_TABLE(i2c, si7020_id);
275
276 static const struct of_device_id si7020_dt_ids[] = {
277         { .compatible = "silabs,si7020" },
278         { }
279 };
280 MODULE_DEVICE_TABLE(of, si7020_dt_ids);
281
282 static struct i2c_driver si7020_driver = {
283         .driver = {
284                 .name = "si7020",
285                 .of_match_table = si7020_dt_ids,
286         },
287         .probe          = si7020_probe,
288         .id_table       = si7020_id,
289 };
290
291 module_i2c_driver(si7020_driver);
292 MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
293 MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
294 MODULE_LICENSE("GPL");