File Index
Files and directories
Sign in
FILE

hs3001.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwmon/hs3001.c C
  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
 43struct hs3001_data {
 44	struct i2c_client *client;
 45	u32 wait_time;		/* in us */
 46	int temperature;	/* in milli degree */
 47	u32 humidity;		/* in milli % */
 48};
 49
 50static int hs3001_extract_temperature(u16 raw)
 51{
 52	/* fixpoint arithmetic 1 digit */
 53	u32 temp = (raw >> 2) * HS3001_FIXPOINT_ARITH * 165;
 54
 55	temp /= (1 << 14) - 1;
 56
 57	return (int)temp - 40 * HS3001_FIXPOINT_ARITH;
 58}
 59
 60static u32 hs3001_extract_humidity(u16 raw)
 61{
 62	u32 hum = (raw & HS3001_MASK_HUMIDITY_0X3FFF) * HS3001_FIXPOINT_ARITH * 100;
 63
 64	return hum / (1 << 14) - 1;
 65}
 66
 67static int hs3001_data_fetch_command(struct i2c_client *client,
 68				     struct hs3001_data *data)
 69{
 70	int ret;
 71	u8 buf[HS3001_RESPONSE_LENGTH];
 72	u8 hs3001_status;
 73
 74	ret = i2c_master_recv(client, buf, HS3001_RESPONSE_LENGTH);
 75	if (ret != HS3001_RESPONSE_LENGTH) {
 76		ret = ret < 0 ? ret : -EIO;
 77		dev_dbg(&client->dev,
 78			"Error in i2c communication. Error code: %d.\n", ret);
 79		return ret;
 80	}
 81
 82	hs3001_status = FIELD_GET(HS3001_MASK_STATUS_0XC0, buf[0]);
 83	if (hs3001_status == HS3001_DATA_STALE) {
 84		dev_dbg(&client->dev, "Sensor busy.\n");
 85		return -EBUSY;
 86	}
 87	if (hs3001_status != HS3001_DATA_VALID) {
 88		dev_dbg(&client->dev, "Data invalid.\n");
 89		return -EIO;
 90	}
 91
 92	data->humidity =
 93		hs3001_extract_humidity(be16_to_cpup((__be16 *)&buf[0]));
 94	data->temperature =
 95		hs3001_extract_temperature(be16_to_cpup((__be16 *)&buf[2]));
 96
 97	return 0;
 98}
 99
100static umode_t hs3001_is_visible(const void *data, enum hwmon_sensor_types type,
101				 u32 attr, int channel)
102{
103	/* Both, humidity and temperature can only be read. */
104	return 0444;
105}
106
107static int hs3001_read(struct device *dev, enum hwmon_sensor_types type,
108		       u32 attr, int channel, long *val)
109{
110	struct hs3001_data *data = dev_get_drvdata(dev);
111	struct i2c_client *client = data->client;
112	int ret;
113
114	ret = i2c_master_send(client, NULL, 0);
115	if (ret < 0)
116		return ret;
117
118	/*
119	 * Sensor needs some time to process measurement depending on
120	 * resolution (ref. datasheet)
121	 */
122	fsleep(data->wait_time);
123
124	ret = hs3001_data_fetch_command(client, data);
125	if (ret < 0)
126		return ret;
127
128	switch (type) {
129	case hwmon_temp:
130		switch (attr) {
131		case hwmon_temp_input:
132			*val = data->temperature;
133			break;
134		default:
135			return -EINVAL;
136		}
137		break;
138	case hwmon_humidity:
139		switch (attr) {
140		case hwmon_humidity_input:
141			*val = data->humidity;
142			break;
143		default:
144			return -EINVAL;
145		}
146		break;
147	default:
148		return -EINVAL;
149	}
150
151	return 0;
152}
153
154static const struct hwmon_channel_info *hs3001_info[] = {
155	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
156	HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
157	NULL
158};
159
160static const struct hwmon_ops hs3001_hwmon_ops = {
161	.is_visible = hs3001_is_visible,
162	.read = hs3001_read,
163};
164
165static const struct hwmon_chip_info hs3001_chip_info = {
166	.ops = &hs3001_hwmon_ops,
167	.info = hs3001_info,
168};
169
170/* device ID table */
171static const struct i2c_device_id hs3001_ids[] = {
172	{ "hs3001" },
173	{ },
174};
175
176MODULE_DEVICE_TABLE(i2c, hs3001_ids);
177
178static const struct of_device_id hs3001_of_match[] = {
179	{.compatible = "renesas,hs3001"},
180	{ },
181};
182
183MODULE_DEVICE_TABLE(of, hs3001_of_match);
184
185static int hs3001_probe(struct i2c_client *client)
186{
187	struct hs3001_data *data;
188	struct device *hwmon_dev;
189	struct device *dev = &client->dev;
190
191	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
192		return -EOPNOTSUPP;
193
194	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
195	if (!data)
196		return -ENOMEM;
197
198	data->client = client;
199
200	/*
201	 * Measurement time = wake-up time + measurement time temperature
202	 * + measurement time humidity. This is currently static, because
203	 * enabling programming mode is not supported, yet.
204	 */
205	data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION +
206			   HS3001_14BIT_RESOLUTION);
207
208	hwmon_dev = devm_hwmon_device_register_with_info(dev,
209							 client->name,
210							 data,
211							 &hs3001_chip_info,
212							 NULL);
213
214	if (IS_ERR(hwmon_dev))
215		return dev_err_probe(dev, PTR_ERR(hwmon_dev),
216				     "Unable to register hwmon device.\n");
217
218	return 0;
219}
220
221static struct i2c_driver hs3001_i2c_driver = {
222	.driver = {
223		   .name = "hs3001",
224		   .of_match_table = hs3001_of_match,
225	},
226	.probe = hs3001_probe,
227	.id_table = hs3001_ids,
228};
229
230module_i2c_driver(hs3001_i2c_driver);
231
232MODULE_AUTHOR("Andre Werner <andre.werner@systec-electronic.com>");
233MODULE_DESCRIPTION("HS3001 humidity and temperature sensor base driver");
234MODULE_LICENSE("GPL");
~/ Read-only file preview.