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_data(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 if (chan->type == IIO_HUMIDITYRELATIVE)
61 *val &= GENMASK(11, 0);
62 return IIO_VAL_INT;
63 case IIO_CHAN_INFO_SCALE:
64 if (chan->type == IIO_TEMP)
65 *val = 175720;
66 else
67 *val = 125 * 1000;
68 *val2 = 65536 >> 2;
69 return IIO_VAL_FRACTIONAL;
70 case IIO_CHAN_INFO_OFFSET:
71
72
73
74
75
76
77
78
79
80 if (chan->type == IIO_TEMP)
81 *val = -4368;
82 else
83 *val = -786;
84 return IIO_VAL_INT;
85 default:
86 break;
87 }
88
89 return -EINVAL;
90}
91
92static const struct iio_chan_spec si7020_channels[] = {
93 {
94 .type = IIO_HUMIDITYRELATIVE,
95 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
96 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
97 },
98 {
99 .type = IIO_TEMP,
100 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
101 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
102 }
103};
104
105static const struct iio_info si7020_info = {
106 .read_raw = si7020_read_raw,
107 .driver_module = THIS_MODULE,
108};
109
110static int si7020_probe(struct i2c_client *client,
111 const struct i2c_device_id *id)
112{
113 struct iio_dev *indio_dev;
114 struct i2c_client **data;
115 int ret;
116
117 if (!i2c_check_functionality(client->adapter,
118 I2C_FUNC_SMBUS_WRITE_BYTE |
119 I2C_FUNC_SMBUS_READ_WORD_DATA))
120 return -ENODEV;
121
122
123 ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
124 if (ret < 0)
125 return ret;
126
127 msleep(15);
128
129 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*client));
130 if (!indio_dev)
131 return -ENOMEM;
132
133 data = iio_priv(indio_dev);
134 *data = client;
135
136 indio_dev->dev.parent = &client->dev;
137 indio_dev->name = dev_name(&client->dev);
138 indio_dev->modes = INDIO_DIRECT_MODE;
139 indio_dev->info = &si7020_info;
140 indio_dev->channels = si7020_channels;
141 indio_dev->num_channels = ARRAY_SIZE(si7020_channels);
142
143 return devm_iio_device_register(&client->dev, indio_dev);
144}
145
146static const struct i2c_device_id si7020_id[] = {
147 { "si7020", 0 },
148 { }
149};
150MODULE_DEVICE_TABLE(i2c, si7020_id);
151
152static struct i2c_driver si7020_driver = {
153 .driver.name = "si7020",
154 .probe = si7020_probe,
155 .id_table = si7020_id,
156};
157
158module_i2c_driver(si7020_driver);
159MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors");
160MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>");
161MODULE_LICENSE("GPL");
162