1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * This is a non-complete driver implementation for the |
4 | * HS3001 humidity and temperature sensor and compatibles. It does not include |
5 | * the configuration possibilities, where it needs to be set to 'programming mode' |
6 | * during power-up. |
7 | * |
8 | * |
9 | * Copyright (C) 2023 SYS TEC electronic AG |
10 | * Author: Andre Werner <andre.werner@systec-electronic.com> |
11 | */ |
12 | |
13 | #include <linux/bitfield.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/err.h> |
16 | #include <linux/hwmon.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/init.h> |
19 | #include <linux/kernel.h> |
20 | #include <linux/module.h> |
21 | #include <linux/of_device.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/types.h> |
24 | |
25 | /* Measurement times */ |
26 | #define HS3001_WAKEUP_TIME 100 /* us */ |
27 | #define HS3001_8BIT_RESOLUTION 550 /* us */ |
28 | #define HS3001_10BIT_RESOLUTION 1310 /* us */ |
29 | #define HS3001_12BIT_RESOLUTION 4500 /* us */ |
30 | #define HS3001_14BIT_RESOLUTION 16900 /* us */ |
31 | |
32 | #define HS3001_RESPONSE_LENGTH 4 |
33 | |
34 | #define HS3001_FIXPOINT_ARITH 1000U |
35 | |
36 | #define HS3001_MASK_HUMIDITY_0X3FFF GENMASK(13, 0) |
37 | #define HS3001_MASK_STATUS_0XC0 GENMASK(7, 6) |
38 | |
39 | /* Definitions for Status Bits of A/D Data */ |
40 | #define HS3001_DATA_VALID 0x00 /* Valid Data */ |
41 | #define HS3001_DATA_STALE 0x01 /* Stale Data */ |
42 | |
43 | struct hs3001_data { |
44 | struct i2c_client *client; |
45 | struct mutex i2c_lock; /* lock for sending i2c commands */ |
46 | u32 wait_time; /* in us */ |
47 | int temperature; /* in milli degree */ |
48 | u32 humidity; /* in milli % */ |
49 | }; |
50 | |
51 | static int (u16 raw) |
52 | { |
53 | /* fixpoint arithmetic 1 digit */ |
54 | u32 temp = (raw >> 2) * HS3001_FIXPOINT_ARITH * 165; |
55 | |
56 | temp /= (1 << 14) - 1; |
57 | |
58 | return (int)temp - 40 * HS3001_FIXPOINT_ARITH; |
59 | } |
60 | |
61 | static u32 (u16 raw) |
62 | { |
63 | u32 hum = (raw & HS3001_MASK_HUMIDITY_0X3FFF) * HS3001_FIXPOINT_ARITH * 100; |
64 | |
65 | return hum / (1 << 14) - 1; |
66 | } |
67 | |
68 | static int hs3001_data_fetch_command(struct i2c_client *client, |
69 | struct hs3001_data *data) |
70 | { |
71 | int ret; |
72 | u8 buf[HS3001_RESPONSE_LENGTH]; |
73 | u8 hs3001_status; |
74 | |
75 | ret = i2c_master_recv(client, buf, HS3001_RESPONSE_LENGTH); |
76 | if (ret != HS3001_RESPONSE_LENGTH) { |
77 | ret = ret < 0 ? ret : -EIO; |
78 | dev_dbg(&client->dev, |
79 | "Error in i2c communication. Error code: %d.\n" , ret); |
80 | return ret; |
81 | } |
82 | |
83 | hs3001_status = FIELD_GET(HS3001_MASK_STATUS_0XC0, buf[0]); |
84 | if (hs3001_status == HS3001_DATA_STALE) { |
85 | dev_dbg(&client->dev, "Sensor busy.\n" ); |
86 | return -EBUSY; |
87 | } |
88 | if (hs3001_status != HS3001_DATA_VALID) { |
89 | dev_dbg(&client->dev, "Data invalid.\n" ); |
90 | return -EIO; |
91 | } |
92 | |
93 | data->humidity = |
94 | hs3001_extract_humidity(be16_to_cpup(p: (__be16 *)&buf[0])); |
95 | data->temperature = |
96 | hs3001_extract_temperature(be16_to_cpup(p: (__be16 *)&buf[2])); |
97 | |
98 | return 0; |
99 | } |
100 | |
101 | static umode_t hs3001_is_visible(const void *data, enum hwmon_sensor_types type, |
102 | u32 attr, int channel) |
103 | { |
104 | /* Both, humidity and temperature can only be read. */ |
105 | return 0444; |
106 | } |
107 | |
108 | static int hs3001_read(struct device *dev, enum hwmon_sensor_types type, |
109 | u32 attr, int channel, long *val) |
110 | { |
111 | struct hs3001_data *data = dev_get_drvdata(dev); |
112 | struct i2c_client *client = data->client; |
113 | int ret; |
114 | |
115 | mutex_lock(&data->i2c_lock); |
116 | ret = i2c_master_send(client, NULL, count: 0); |
117 | if (ret < 0) { |
118 | mutex_unlock(lock: &data->i2c_lock); |
119 | return ret; |
120 | } |
121 | |
122 | /* |
123 | * Sensor needs some time to process measurement depending on |
124 | * resolution (ref. datasheet) |
125 | */ |
126 | fsleep(usecs: data->wait_time); |
127 | |
128 | ret = hs3001_data_fetch_command(client, data); |
129 | mutex_unlock(lock: &data->i2c_lock); |
130 | |
131 | if (ret < 0) |
132 | return ret; |
133 | |
134 | switch (type) { |
135 | case hwmon_temp: |
136 | switch (attr) { |
137 | case hwmon_temp_input: |
138 | *val = data->temperature; |
139 | break; |
140 | default: |
141 | return -EINVAL; |
142 | } |
143 | break; |
144 | case hwmon_humidity: |
145 | switch (attr) { |
146 | case hwmon_humidity_input: |
147 | *val = data->humidity; |
148 | break; |
149 | default: |
150 | return -EINVAL; |
151 | } |
152 | break; |
153 | default: |
154 | return -EINVAL; |
155 | } |
156 | |
157 | return 0; |
158 | } |
159 | |
160 | static const struct hwmon_channel_info *hs3001_info[] = { |
161 | HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), |
162 | HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT), |
163 | NULL |
164 | }; |
165 | |
166 | static const struct hwmon_ops hs3001_hwmon_ops = { |
167 | .is_visible = hs3001_is_visible, |
168 | .read = hs3001_read, |
169 | }; |
170 | |
171 | static const struct hwmon_chip_info hs3001_chip_info = { |
172 | .ops = &hs3001_hwmon_ops, |
173 | .info = hs3001_info, |
174 | }; |
175 | |
176 | /* device ID table */ |
177 | static const struct i2c_device_id hs3001_ids[] = { |
178 | { "hs3001" , 0 }, |
179 | { }, |
180 | }; |
181 | |
182 | MODULE_DEVICE_TABLE(i2c, hs3001_ids); |
183 | |
184 | static const struct of_device_id hs3001_of_match[] = { |
185 | {.compatible = "renesas,hs3001" }, |
186 | { }, |
187 | }; |
188 | |
189 | MODULE_DEVICE_TABLE(of, hs3001_of_match); |
190 | |
191 | static int hs3001_probe(struct i2c_client *client) |
192 | { |
193 | struct hs3001_data *data; |
194 | struct device *hwmon_dev; |
195 | struct device *dev = &client->dev; |
196 | |
197 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_I2C)) |
198 | return -EOPNOTSUPP; |
199 | |
200 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
201 | if (!data) |
202 | return -ENOMEM; |
203 | |
204 | data->client = client; |
205 | |
206 | /* |
207 | * Measurement time = wake-up time + measurement time temperature |
208 | * + measurement time humidity. This is currently static, because |
209 | * enabling programming mode is not supported, yet. |
210 | */ |
211 | data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION + |
212 | HS3001_14BIT_RESOLUTION); |
213 | |
214 | mutex_init(&data->i2c_lock); |
215 | |
216 | hwmon_dev = devm_hwmon_device_register_with_info(dev, |
217 | name: client->name, |
218 | drvdata: data, |
219 | info: &hs3001_chip_info, |
220 | NULL); |
221 | |
222 | if (IS_ERR(ptr: hwmon_dev)) |
223 | return dev_err_probe(dev, err: PTR_ERR(ptr: hwmon_dev), |
224 | fmt: "Unable to register hwmon device.\n" ); |
225 | |
226 | return 0; |
227 | } |
228 | |
229 | static struct i2c_driver hs3001_i2c_driver = { |
230 | .driver = { |
231 | .name = "hs3001" , |
232 | .of_match_table = hs3001_of_match, |
233 | }, |
234 | .probe = hs3001_probe, |
235 | .id_table = hs3001_ids, |
236 | }; |
237 | |
238 | module_i2c_driver(hs3001_i2c_driver); |
239 | |
240 | MODULE_AUTHOR("Andre Werner <andre.werner@systec-electronic.com>" ); |
241 | MODULE_DESCRIPTION("HS3001 humidity and temperature sensor base driver" ); |
242 | MODULE_LICENSE("GPL" ); |
243 | |