1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28#include <linux/delay.h>
29#include <linux/i2c.h>
30#include <linux/module.h>
31#include <linux/slab.h>
32#include <linux/sysfs.h>
33
34#include <linux/iio/iio.h>
35#include <linux/iio/sysfs.h>
36
37
38#define SI7020CMD_RH_HOLD 0xE5
39
40#define SI7020CMD_TEMP_HOLD 0xE3
41
42#define SI7020CMD_RESET 0xFE
43
44static int si7020_read_raw(struct iio_dev *indio_dev,
45 struct iio_chan_spec const *chan, int *val,
46 int *val2, long mask)
47{
48 struct i2c_client **client = iio_priv(indio_dev);
49 int ret;
50
51 switch (mask) {
52 case IIO_CHAN_INFO_RAW:
53 ret = i2c_smbus_read_word_swapped(*client,
54 chan->type == IIO_TEMP ?
55 SI7020CMD_TEMP_HOLD :
56 SI7020CMD_RH_HOLD);
57 if (ret < 0)
58 return ret;
59 *val = ret >> 2;
60
61
62
63
64 if (chan->type == IIO_HUMIDITYRELATIVE)
65 *val = clamp_val(*val, 786, 13893);
66 return IIO_VAL_INT;
67 case IIO_CHAN_INFO_SCALE:
68 if (chan->type == IIO_TEMP)
69 *val = 175720;
70 else
71 *val = 125 * 1000;
72 *val2 = 65536 >> 2;
73 return IIO_VAL_FRACTIONAL;
74 case IIO_CHAN_INFO_OFFSET:
75
76
77
78
79
80
81
82
83
84 if (chan->type == IIO_TEMP)
85 *val = -4368;
86 else
87 *val = -786;
88 return IIO_VAL_INT;
89 default:
90 break;
91 }
92
93 return -EINVAL;
94}
95
96static const struct iio_chan_spec si7020_channels[] = {
97 {
98 .type = IIO_HUMIDITYRELATIVE,
99 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
100 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
101 },
102 {
103 .type = IIO_TEMP,
104 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
105 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
106 }
107};
108
109static const struct iio_info si7020_info = {
110 .read_raw = si7020_read_raw,
111 .driver_module = THIS_MODULE,
112};
113
114static int si7020_probe(struct i2c_client *client,
115 const struct i2c_device_id *id)
116{
117 struct iio_dev *indio_dev;
118 struct i2c_client **data;
119 int ret;
120
121 if (!i2c_check_functionality(client->adapter,
122 I2C_FUNC_SMBUS_WRITE_BYTE |
123 I2C_FUNC_SMBUS_READ_WORD_DATA))
124 return -EOPNOTSUPP;
125
126
127 ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
128 if (ret < 0)
129 return ret;
130
131 msleep(15);
132
133 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
134 if (!indio_dev)
135 return -ENOMEM;
136
137 data = iio_priv(indio_dev);
138 *data = client;
139
140 indio_dev->dev.parent = &client->dev;
141 indio_dev->name = dev_name(&client->dev);
142 indio_dev->modes = INDIO_DIRECT_MODE;
143 indio_dev->info = &si7020_info;
144 indio_dev->channels = si7020_channels;
145 indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
146
147 return devm_iio_device_register(&client->dev, indio_dev);
148}
149
150static const struct i2c_device_id si7020_id[] = {
151 { "si7020", 0 },
152 { "th06", 0 },
153 { }
154};
155MODULE_DEVICE_TABLE(i2c, si7020_id);
156
157static const struct of_device_id si7020_dt_ids[] = {
158 { .compatible = "silabs,si7020" },
159 { }
160};
161MODULE_DEVICE_TABLE(of, si7020_dt_ids);
162
163static struct i2c_driver si7020_driver = {
164 .driver = {
165 .name = "si7020",
166 .of_match_table = of_match_ptr(si7020_dt_ids),
167 },
168 .probe = si7020_probe,
169 .id_table = si7020_id,
170};
171
172module_i2c_driver(si7020_driver);
173MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
174MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
175MODULE_LICENSE("GPL");
176