xref: /openbmc/linux/drivers/hwmon/shtc1.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21a539d37STomas Pop /* Sensirion SHTC1 humidity and temperature sensor driver
31a539d37STomas Pop  *
41a539d37STomas Pop  * Copyright (C) 2014 Sensirion AG, Switzerland
51a539d37STomas Pop  * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.com>
61a539d37STomas Pop  */
71a539d37STomas Pop 
81a539d37STomas Pop #include <linux/module.h>
91a539d37STomas Pop #include <linux/init.h>
101a539d37STomas Pop #include <linux/slab.h>
111a539d37STomas Pop #include <linux/i2c.h>
121a539d37STomas Pop #include <linux/hwmon.h>
131a539d37STomas Pop #include <linux/hwmon-sysfs.h>
141a539d37STomas Pop #include <linux/err.h>
151a539d37STomas Pop #include <linux/delay.h>
161a539d37STomas Pop #include <linux/platform_data/shtc1.h>
17be7373b6SChris Ruehl #include <linux/of.h>
181a539d37STomas Pop 
191a539d37STomas Pop /* commands (high precision mode) */
201a539d37STomas Pop static const unsigned char shtc1_cmd_measure_blocking_hpm[]    = { 0x7C, 0xA2 };
211a539d37STomas Pop static const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 };
221a539d37STomas Pop 
231a539d37STomas Pop /* commands (low precision mode) */
241a539d37STomas Pop static const unsigned char shtc1_cmd_measure_blocking_lpm[]    = { 0x64, 0x58 };
251a539d37STomas Pop static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
261a539d37STomas Pop 
271a539d37STomas Pop /* command for reading the ID register */
281a539d37STomas Pop static const unsigned char shtc1_cmd_read_id_reg[]             = { 0xef, 0xc8 };
291a539d37STomas Pop 
30ffd96868SDan Robertson /*
31ffd96868SDan Robertson  * constants for reading the ID register
32ffd96868SDan Robertson  * SHTC1: 0x0007 with mask 0x003f
33ffd96868SDan Robertson  * SHTW1: 0x0007 with mask 0x003f
34ffd96868SDan Robertson  * SHTC3: 0x0807 with mask 0x083f
35ffd96868SDan Robertson  */
36ffd96868SDan Robertson #define SHTC3_ID      0x0807
37ffd96868SDan Robertson #define SHTC3_ID_MASK 0x083f
38ffd96868SDan Robertson #define SHTC1_ID      0x0007
39ffd96868SDan Robertson #define SHTC1_ID_MASK 0x003f
401a539d37STomas Pop 
411a539d37STomas Pop /* delays for non-blocking i2c commands, both in us */
421a539d37STomas Pop #define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
431a539d37STomas Pop #define SHTC1_NONBLOCKING_WAIT_TIME_LPM   1000
44ffd96868SDan Robertson #define SHTC3_NONBLOCKING_WAIT_TIME_HPM  12100
45ffd96868SDan Robertson #define SHTC3_NONBLOCKING_WAIT_TIME_LPM    800
461a539d37STomas Pop 
471a539d37STomas Pop #define SHTC1_CMD_LENGTH      2
481a539d37STomas Pop #define SHTC1_RESPONSE_LENGTH 6
491a539d37STomas Pop 
50ffd96868SDan Robertson enum shtcx_chips {
51ffd96868SDan Robertson 	shtc1,
52ffd96868SDan Robertson 	shtc3,
53ffd96868SDan Robertson };
54ffd96868SDan Robertson 
551a539d37STomas Pop struct shtc1_data {
561a539d37STomas Pop 	struct i2c_client *client;
571a539d37STomas Pop 	struct mutex update_lock;
581a539d37STomas Pop 	bool valid;
591a539d37STomas Pop 	unsigned long last_updated; /* in jiffies */
601a539d37STomas Pop 
611a539d37STomas Pop 	const unsigned char *command;
621a539d37STomas Pop 	unsigned int nonblocking_wait_time; /* in us */
631a539d37STomas Pop 
641a539d37STomas Pop 	struct shtc1_platform_data setup;
65ffd96868SDan Robertson 	enum shtcx_chips chip;
661a539d37STomas Pop 
671a539d37STomas Pop 	int temperature; /* 1000 * temperature in dgr C */
681a539d37STomas Pop 	int humidity; /* 1000 * relative humidity in %RH */
691a539d37STomas Pop };
701a539d37STomas Pop 
shtc1_update_values(struct i2c_client * client,struct shtc1_data * data,char * buf,int bufsize)711a539d37STomas Pop static int shtc1_update_values(struct i2c_client *client,
721a539d37STomas Pop 			       struct shtc1_data *data,
731a539d37STomas Pop 			       char *buf, int bufsize)
741a539d37STomas Pop {
751a539d37STomas Pop 	int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH);
761a539d37STomas Pop 	if (ret != SHTC1_CMD_LENGTH) {
771a539d37STomas Pop 		dev_err(&client->dev, "failed to send command: %d\n", ret);
781a539d37STomas Pop 		return ret < 0 ? ret : -EIO;
791a539d37STomas Pop 	}
801a539d37STomas Pop 
811a539d37STomas Pop 	/*
821a539d37STomas Pop 	 * In blocking mode (clock stretching mode) the I2C bus
831a539d37STomas Pop 	 * is blocked for other traffic, thus the call to i2c_master_recv()
841a539d37STomas Pop 	 * will wait until the data is ready. For non blocking mode, we
851a539d37STomas Pop 	 * have to wait ourselves.
861a539d37STomas Pop 	 */
871a539d37STomas Pop 	if (!data->setup.blocking_io)
881a539d37STomas Pop 		usleep_range(data->nonblocking_wait_time,
891a539d37STomas Pop 			     data->nonblocking_wait_time + 1000);
901a539d37STomas Pop 
911a539d37STomas Pop 	ret = i2c_master_recv(client, buf, bufsize);
921a539d37STomas Pop 	if (ret != bufsize) {
931a539d37STomas Pop 		dev_err(&client->dev, "failed to read values: %d\n", ret);
941a539d37STomas Pop 		return ret < 0 ? ret : -EIO;
951a539d37STomas Pop 	}
961a539d37STomas Pop 
971a539d37STomas Pop 	return 0;
981a539d37STomas Pop }
991a539d37STomas Pop 
1001a539d37STomas Pop /* sysfs attributes */
shtc1_update_client(struct device * dev)1011a539d37STomas Pop static struct shtc1_data *shtc1_update_client(struct device *dev)
1021a539d37STomas Pop {
1031a539d37STomas Pop 	struct shtc1_data *data = dev_get_drvdata(dev);
1041a539d37STomas Pop 	struct i2c_client *client = data->client;
1051a539d37STomas Pop 	unsigned char buf[SHTC1_RESPONSE_LENGTH];
1061a539d37STomas Pop 	int val;
1071a539d37STomas Pop 	int ret = 0;
1081a539d37STomas Pop 
1091a539d37STomas Pop 	mutex_lock(&data->update_lock);
1101a539d37STomas Pop 
1111a539d37STomas Pop 	if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
1121a539d37STomas Pop 		ret = shtc1_update_values(client, data, buf, sizeof(buf));
1131a539d37STomas Pop 		if (ret)
1141a539d37STomas Pop 			goto out;
1151a539d37STomas Pop 
1161a539d37STomas Pop 		/*
1171a539d37STomas Pop 		 * From datasheet:
1181a539d37STomas Pop 		 * T = -45 + 175 * ST / 2^16
1191a539d37STomas Pop 		 * RH = 100 * SRH / 2^16
1201a539d37STomas Pop 		 *
1211a539d37STomas Pop 		 * Adapted for integer fixed point (3 digit) arithmetic.
1221a539d37STomas Pop 		 */
1231a539d37STomas Pop 		val = be16_to_cpup((__be16 *)buf);
1241a539d37STomas Pop 		data->temperature = ((21875 * val) >> 13) - 45000;
1251a539d37STomas Pop 		val = be16_to_cpup((__be16 *)(buf + 3));
1261a539d37STomas Pop 		data->humidity = ((12500 * val) >> 13);
1271a539d37STomas Pop 
1281a539d37STomas Pop 		data->last_updated = jiffies;
1291a539d37STomas Pop 		data->valid = true;
1301a539d37STomas Pop 	}
1311a539d37STomas Pop 
1321a539d37STomas Pop out:
1331a539d37STomas Pop 	mutex_unlock(&data->update_lock);
1341a539d37STomas Pop 
1351a539d37STomas Pop 	return ret == 0 ? data : ERR_PTR(ret);
1361a539d37STomas Pop }
1371a539d37STomas Pop 
temp1_input_show(struct device * dev,struct device_attribute * attr,char * buf)1381a539d37STomas Pop static ssize_t temp1_input_show(struct device *dev,
1391a539d37STomas Pop 				struct device_attribute *attr,
1401a539d37STomas Pop 				char *buf)
1411a539d37STomas Pop {
1421a539d37STomas Pop 	struct shtc1_data *data = shtc1_update_client(dev);
1431a539d37STomas Pop 	if (IS_ERR(data))
1441a539d37STomas Pop 		return PTR_ERR(data);
1451a539d37STomas Pop 
1461a539d37STomas Pop 	return sprintf(buf, "%d\n", data->temperature);
1471a539d37STomas Pop }
1481a539d37STomas Pop 
humidity1_input_show(struct device * dev,struct device_attribute * attr,char * buf)1491a539d37STomas Pop static ssize_t humidity1_input_show(struct device *dev,
1501a539d37STomas Pop 				    struct device_attribute *attr, char *buf)
1511a539d37STomas Pop {
1521a539d37STomas Pop 	struct shtc1_data *data = shtc1_update_client(dev);
1531a539d37STomas Pop 	if (IS_ERR(data))
1541a539d37STomas Pop 		return PTR_ERR(data);
1551a539d37STomas Pop 
1561a539d37STomas Pop 	return sprintf(buf, "%d\n", data->humidity);
1571a539d37STomas Pop }
1581a539d37STomas Pop 
1591a539d37STomas Pop static DEVICE_ATTR_RO(temp1_input);
1601a539d37STomas Pop static DEVICE_ATTR_RO(humidity1_input);
1611a539d37STomas Pop 
1621a539d37STomas Pop static struct attribute *shtc1_attrs[] = {
1631a539d37STomas Pop 	&dev_attr_temp1_input.attr,
1641a539d37STomas Pop 	&dev_attr_humidity1_input.attr,
1651a539d37STomas Pop 	NULL
1661a539d37STomas Pop };
1671a539d37STomas Pop 
1681a539d37STomas Pop ATTRIBUTE_GROUPS(shtc1);
1691a539d37STomas Pop 
shtc1_select_command(struct shtc1_data * data)1701a539d37STomas Pop static void shtc1_select_command(struct shtc1_data *data)
1711a539d37STomas Pop {
1721a539d37STomas Pop 	if (data->setup.high_precision) {
1731a539d37STomas Pop 		data->command = data->setup.blocking_io ?
1741a539d37STomas Pop 				shtc1_cmd_measure_blocking_hpm :
1751a539d37STomas Pop 				shtc1_cmd_measure_nonblocking_hpm;
176ffd96868SDan Robertson 		data->nonblocking_wait_time = (data->chip == shtc1) ?
177ffd96868SDan Robertson 				SHTC1_NONBLOCKING_WAIT_TIME_HPM :
178ffd96868SDan Robertson 				SHTC3_NONBLOCKING_WAIT_TIME_HPM;
1791a539d37STomas Pop 	} else {
1801a539d37STomas Pop 		data->command = data->setup.blocking_io ?
1811a539d37STomas Pop 				shtc1_cmd_measure_blocking_lpm :
1821a539d37STomas Pop 				shtc1_cmd_measure_nonblocking_lpm;
183ffd96868SDan Robertson 		data->nonblocking_wait_time = (data->chip == shtc1) ?
184ffd96868SDan Robertson 				SHTC1_NONBLOCKING_WAIT_TIME_LPM :
185ffd96868SDan Robertson 				SHTC3_NONBLOCKING_WAIT_TIME_LPM;
1861a539d37STomas Pop 	}
1871a539d37STomas Pop }
1881a539d37STomas Pop 
18967487038SStephen Kitt static const struct i2c_device_id shtc1_id[];
19067487038SStephen Kitt 
shtc1_probe(struct i2c_client * client)19167487038SStephen Kitt static int shtc1_probe(struct i2c_client *client)
1921a539d37STomas Pop {
1931a539d37STomas Pop 	int ret;
194ffd96868SDan Robertson 	u16 id_reg;
195ffd96868SDan Robertson 	char id_reg_buf[2];
1961a539d37STomas Pop 	struct shtc1_data *data;
1971a539d37STomas Pop 	struct device *hwmon_dev;
19867487038SStephen Kitt 	enum shtcx_chips chip = i2c_match_id(shtc1_id, client)->driver_data;
1991a539d37STomas Pop 	struct i2c_adapter *adap = client->adapter;
2001a539d37STomas Pop 	struct device *dev = &client->dev;
201be7373b6SChris Ruehl 	struct device_node *np = dev->of_node;
2021a539d37STomas Pop 
2031a539d37STomas Pop 	if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) {
2041a539d37STomas Pop 		dev_err(dev, "plain i2c transactions not supported\n");
2051a539d37STomas Pop 		return -ENODEV;
2061a539d37STomas Pop 	}
2071a539d37STomas Pop 
2081a539d37STomas Pop 	ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH);
2091a539d37STomas Pop 	if (ret != SHTC1_CMD_LENGTH) {
2101a539d37STomas Pop 		dev_err(dev, "could not send read_id_reg command: %d\n", ret);
2111a539d37STomas Pop 		return ret < 0 ? ret : -ENODEV;
2121a539d37STomas Pop 	}
213ffd96868SDan Robertson 	ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));
214ffd96868SDan Robertson 	if (ret != sizeof(id_reg_buf)) {
2151a539d37STomas Pop 		dev_err(dev, "could not read ID register: %d\n", ret);
2161a539d37STomas Pop 		return -ENODEV;
2171a539d37STomas Pop 	}
218ffd96868SDan Robertson 
219ffd96868SDan Robertson 	id_reg = be16_to_cpup((__be16 *)id_reg_buf);
220ffd96868SDan Robertson 	if (chip == shtc3) {
221ffd96868SDan Robertson 		if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) {
222ffd96868SDan Robertson 			dev_err(dev, "SHTC3 ID register does not match\n");
223ffd96868SDan Robertson 			return -ENODEV;
224ffd96868SDan Robertson 		}
225ffd96868SDan Robertson 	} else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) {
226ffd96868SDan Robertson 		dev_err(dev, "SHTC1 ID register does not match\n");
2271a539d37STomas Pop 		return -ENODEV;
2281a539d37STomas Pop 	}
2291a539d37STomas Pop 
2301a539d37STomas Pop 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
2311a539d37STomas Pop 	if (!data)
2321a539d37STomas Pop 		return -ENOMEM;
2331a539d37STomas Pop 
2341a539d37STomas Pop 	data->setup.blocking_io = false;
2351a539d37STomas Pop 	data->setup.high_precision = true;
2361a539d37STomas Pop 	data->client = client;
237ffd96868SDan Robertson 	data->chip = chip;
2381a539d37STomas Pop 
239be7373b6SChris Ruehl 	if (np) {
240be7373b6SChris Ruehl 		data->setup.blocking_io = of_property_read_bool(np, "sensirion,blocking-io");
241*e67cae42SGuenter Roeck 		data->setup.high_precision = !of_property_read_bool(np, "sensirion,low-precision");
242be7373b6SChris Ruehl 	} else {
2431a539d37STomas Pop 		if (client->dev.platform_data)
2441a539d37STomas Pop 			data->setup = *(struct shtc1_platform_data *)dev->platform_data;
245be7373b6SChris Ruehl 	}
246be7373b6SChris Ruehl 
2471a539d37STomas Pop 	shtc1_select_command(data);
2481a539d37STomas Pop 	mutex_init(&data->update_lock);
2491a539d37STomas Pop 
2501a539d37STomas Pop 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
2511a539d37STomas Pop 							   client->name,
2521a539d37STomas Pop 							   data,
2531a539d37STomas Pop 							   shtc1_groups);
2541a539d37STomas Pop 	if (IS_ERR(hwmon_dev))
2551a539d37STomas Pop 		dev_dbg(dev, "unable to register hwmon device\n");
2561a539d37STomas Pop 
2571a539d37STomas Pop 	return PTR_ERR_OR_ZERO(hwmon_dev);
2581a539d37STomas Pop }
2591a539d37STomas Pop 
2601a539d37STomas Pop /* device ID table */
2611a539d37STomas Pop static const struct i2c_device_id shtc1_id[] = {
262ffd96868SDan Robertson 	{ "shtc1", shtc1 },
263ffd96868SDan Robertson 	{ "shtw1", shtc1 },
264ffd96868SDan Robertson 	{ "shtc3", shtc3 },
2651a539d37STomas Pop 	{ }
2661a539d37STomas Pop };
2671a539d37STomas Pop MODULE_DEVICE_TABLE(i2c, shtc1_id);
2681a539d37STomas Pop 
269be7373b6SChris Ruehl static const struct of_device_id shtc1_of_match[] = {
270be7373b6SChris Ruehl 	{ .compatible = "sensirion,shtc1" },
271be7373b6SChris Ruehl 	{ .compatible = "sensirion,shtw1" },
272be7373b6SChris Ruehl 	{ .compatible = "sensirion,shtc3" },
273be7373b6SChris Ruehl 	{ }
274be7373b6SChris Ruehl };
275be7373b6SChris Ruehl MODULE_DEVICE_TABLE(of, shtc1_of_match);
276be7373b6SChris Ruehl 
2771a539d37STomas Pop static struct i2c_driver shtc1_i2c_driver = {
278be7373b6SChris Ruehl 	.driver = {
279be7373b6SChris Ruehl 		.name = "shtc1",
280be7373b6SChris Ruehl 		.of_match_table = shtc1_of_match,
281be7373b6SChris Ruehl 	},
2821975d167SUwe Kleine-König 	.probe        = shtc1_probe,
2831a539d37STomas Pop 	.id_table     = shtc1_id,
2841a539d37STomas Pop };
2851a539d37STomas Pop 
2861a539d37STomas Pop module_i2c_driver(shtc1_i2c_driver);
2871a539d37STomas Pop 
2881a539d37STomas Pop MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>");
2891a539d37STomas Pop MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver");
2901a539d37STomas Pop MODULE_LICENSE("GPL");
291