diff options
Diffstat (limited to 'drivers/iio/humidity/si7020.c')
-rw-r--r-- | drivers/iio/humidity/si7020.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c new file mode 100644 index 000000000000..b54164677b89 --- /dev/null +++ b/drivers/iio/humidity/si7020.c | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * si7020.c - Silicon Labs Si7013/20/21 Relative Humidity and Temp Sensors | ||
3 | * Copyright (c) 2013,2014 Uplogix, Inc. | ||
4 | * David Barksdale <dbarksdale@uplogix.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * The Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors | ||
18 | * are i2c devices which have an identical programming interface for | ||
19 | * measuring relative humidity and temperature. The Si7013 has an additional | ||
20 | * temperature input which this driver does not support. | ||
21 | * | ||
22 | * Data Sheets: | ||
23 | * Si7013: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf | ||
24 | * Si7020: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf | ||
25 | * Si7021: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf | ||
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 | /* Measure Relative Humidity, Hold Master Mode */ | ||
38 | #define SI7020CMD_RH_HOLD 0xE5 | ||
39 | /* Measure Temperature, Hold Master Mode */ | ||
40 | #define SI7020CMD_TEMP_HOLD 0xE3 | ||
41 | /* Software Reset */ | ||
42 | #define SI7020CMD_RESET 0xFE | ||
43 | |||
44 | static 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; /* = 175.72 * 1000 */ | ||
66 | else | ||
67 | *val = 125 * 1000; | ||
68 | *val2 = 65536 >> 2; | ||
69 | return IIO_VAL_FRACTIONAL; | ||
70 | case IIO_CHAN_INFO_OFFSET: | ||
71 | /* | ||
72 | * Since iio_convert_raw_to_processed_unlocked assumes offset | ||
73 | * is an integer we have to round these values and lose | ||
74 | * accuracy. | ||
75 | * Relative humidity will be 0.0032959% too high and | ||
76 | * temperature will be 0.00277344 degrees too high. | ||
77 | * This is no big deal because it's within the accuracy of the | ||
78 | * sensor. | ||
79 | */ | ||
80 | if (chan->type == IIO_TEMP) | ||
81 | *val = -4368; /* = -46.85 * (65536 >> 2) / 175.72 */ | ||
82 | else | ||
83 | *val = -786; /* = -6 * (65536 >> 2) / 125 */ | ||
84 | return IIO_VAL_INT; | ||
85 | default: | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | static 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 | |||
105 | static const struct iio_info si7020_info = { | ||
106 | .read_raw = si7020_read_raw, | ||
107 | .driver_module = THIS_MODULE, | ||
108 | }; | ||
109 | |||
110 | static 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 | /* Reset device, loads default settings. */ | ||
123 | ret = i2c_smbus_write_byte(client, SI7020CMD_RESET); | ||
124 | if (ret < 0) | ||
125 | return ret; | ||
126 | /* Wait the maximum power-up time after software reset. */ | ||
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 | |||
146 | static const struct i2c_device_id si7020_id[] = { | ||
147 | { "si7020", 0 }, | ||
148 | { } | ||
149 | }; | ||
150 | MODULE_DEVICE_TABLE(i2c, si7020_id); | ||
151 | |||
152 | static struct i2c_driver si7020_driver = { | ||
153 | .driver.name = "si7020", | ||
154 | .probe = si7020_probe, | ||
155 | .id_table = si7020_id, | ||
156 | }; | ||
157 | |||
158 | module_i2c_driver(si7020_driver); | ||
159 | MODULE_DESCRIPTION("Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors"); | ||
160 | MODULE_AUTHOR("David Barksdale <dbarksdale@uplogix.com>"); | ||
161 | MODULE_LICENSE("GPL"); | ||