xref: /openbmc/linux/drivers/hwmon/shtc1.c (revision ffd96868ac5d4c22bba1ba2175d124cb2775f3f7)
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>
171a539d37STomas Pop 
181a539d37STomas Pop /* commands (high precision mode) */
191a539d37STomas Pop static const unsigned char shtc1_cmd_measure_blocking_hpm[]    = { 0x7C, 0xA2 };
201a539d37STomas Pop static const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 };
211a539d37STomas Pop 
221a539d37STomas Pop /* commands (low precision mode) */
231a539d37STomas Pop static const unsigned char shtc1_cmd_measure_blocking_lpm[]    = { 0x64, 0x58 };
241a539d37STomas Pop static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
251a539d37STomas Pop 
261a539d37STomas Pop /* command for reading the ID register */
271a539d37STomas Pop static const unsigned char shtc1_cmd_read_id_reg[]             = { 0xef, 0xc8 };
281a539d37STomas Pop 
29*ffd96868SDan Robertson /*
30*ffd96868SDan Robertson  * constants for reading the ID register
31*ffd96868SDan Robertson  * SHTC1: 0x0007 with mask 0x003f
32*ffd96868SDan Robertson  * SHTW1: 0x0007 with mask 0x003f
33*ffd96868SDan Robertson  * SHTC3: 0x0807 with mask 0x083f
34*ffd96868SDan Robertson  */
35*ffd96868SDan Robertson #define SHTC3_ID      0x0807
36*ffd96868SDan Robertson #define SHTC3_ID_MASK 0x083f
37*ffd96868SDan Robertson #define SHTC1_ID      0x0007
38*ffd96868SDan Robertson #define SHTC1_ID_MASK 0x003f
391a539d37STomas Pop 
401a539d37STomas Pop /* delays for non-blocking i2c commands, both in us */
411a539d37STomas Pop #define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
421a539d37STomas Pop #define SHTC1_NONBLOCKING_WAIT_TIME_LPM   1000
43*ffd96868SDan Robertson #define SHTC3_NONBLOCKING_WAIT_TIME_HPM  12100
44*ffd96868SDan Robertson #define SHTC3_NONBLOCKING_WAIT_TIME_LPM    800
451a539d37STomas Pop 
461a539d37STomas Pop #define SHTC1_CMD_LENGTH      2
471a539d37STomas Pop #define SHTC1_RESPONSE_LENGTH 6
481a539d37STomas Pop 
49*ffd96868SDan Robertson enum shtcx_chips {
50*ffd96868SDan Robertson 	shtc1,
51*ffd96868SDan Robertson 	shtc3,
52*ffd96868SDan Robertson };
53*ffd96868SDan Robertson 
541a539d37STomas Pop struct shtc1_data {
551a539d37STomas Pop 	struct i2c_client *client;
561a539d37STomas Pop 	struct mutex update_lock;
571a539d37STomas Pop 	bool valid;
581a539d37STomas Pop 	unsigned long last_updated; /* in jiffies */
591a539d37STomas Pop 
601a539d37STomas Pop 	const unsigned char *command;
611a539d37STomas Pop 	unsigned int nonblocking_wait_time; /* in us */
621a539d37STomas Pop 
631a539d37STomas Pop 	struct shtc1_platform_data setup;
64*ffd96868SDan Robertson 	enum shtcx_chips chip;
651a539d37STomas Pop 
661a539d37STomas Pop 	int temperature; /* 1000 * temperature in dgr C */
671a539d37STomas Pop 	int humidity; /* 1000 * relative humidity in %RH */
681a539d37STomas Pop };
691a539d37STomas Pop 
701a539d37STomas Pop static int shtc1_update_values(struct i2c_client *client,
711a539d37STomas Pop 			       struct shtc1_data *data,
721a539d37STomas Pop 			       char *buf, int bufsize)
731a539d37STomas Pop {
741a539d37STomas Pop 	int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH);
751a539d37STomas Pop 	if (ret != SHTC1_CMD_LENGTH) {
761a539d37STomas Pop 		dev_err(&client->dev, "failed to send command: %d\n", ret);
771a539d37STomas Pop 		return ret < 0 ? ret : -EIO;
781a539d37STomas Pop 	}
791a539d37STomas Pop 
801a539d37STomas Pop 	/*
811a539d37STomas Pop 	 * In blocking mode (clock stretching mode) the I2C bus
821a539d37STomas Pop 	 * is blocked for other traffic, thus the call to i2c_master_recv()
831a539d37STomas Pop 	 * will wait until the data is ready. For non blocking mode, we
841a539d37STomas Pop 	 * have to wait ourselves.
851a539d37STomas Pop 	 */
861a539d37STomas Pop 	if (!data->setup.blocking_io)
871a539d37STomas Pop 		usleep_range(data->nonblocking_wait_time,
881a539d37STomas Pop 			     data->nonblocking_wait_time + 1000);
891a539d37STomas Pop 
901a539d37STomas Pop 	ret = i2c_master_recv(client, buf, bufsize);
911a539d37STomas Pop 	if (ret != bufsize) {
921a539d37STomas Pop 		dev_err(&client->dev, "failed to read values: %d\n", ret);
931a539d37STomas Pop 		return ret < 0 ? ret : -EIO;
941a539d37STomas Pop 	}
951a539d37STomas Pop 
961a539d37STomas Pop 	return 0;
971a539d37STomas Pop }
981a539d37STomas Pop 
991a539d37STomas Pop /* sysfs attributes */
1001a539d37STomas Pop static struct shtc1_data *shtc1_update_client(struct device *dev)
1011a539d37STomas Pop {
1021a539d37STomas Pop 	struct shtc1_data *data = dev_get_drvdata(dev);
1031a539d37STomas Pop 	struct i2c_client *client = data->client;
1041a539d37STomas Pop 	unsigned char buf[SHTC1_RESPONSE_LENGTH];
1051a539d37STomas Pop 	int val;
1061a539d37STomas Pop 	int ret = 0;
1071a539d37STomas Pop 
1081a539d37STomas Pop 	mutex_lock(&data->update_lock);
1091a539d37STomas Pop 
1101a539d37STomas Pop 	if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
1111a539d37STomas Pop 		ret = shtc1_update_values(client, data, buf, sizeof(buf));
1121a539d37STomas Pop 		if (ret)
1131a539d37STomas Pop 			goto out;
1141a539d37STomas Pop 
1151a539d37STomas Pop 		/*
1161a539d37STomas Pop 		 * From datasheet:
1171a539d37STomas Pop 		 * T = -45 + 175 * ST / 2^16
1181a539d37STomas Pop 		 * RH = 100 * SRH / 2^16
1191a539d37STomas Pop 		 *
1201a539d37STomas Pop 		 * Adapted for integer fixed point (3 digit) arithmetic.
1211a539d37STomas Pop 		 */
1221a539d37STomas Pop 		val = be16_to_cpup((__be16 *)buf);
1231a539d37STomas Pop 		data->temperature = ((21875 * val) >> 13) - 45000;
1241a539d37STomas Pop 		val = be16_to_cpup((__be16 *)(buf + 3));
1251a539d37STomas Pop 		data->humidity = ((12500 * val) >> 13);
1261a539d37STomas Pop 
1271a539d37STomas Pop 		data->last_updated = jiffies;
1281a539d37STomas Pop 		data->valid = true;
1291a539d37STomas Pop 	}
1301a539d37STomas Pop 
1311a539d37STomas Pop out:
1321a539d37STomas Pop 	mutex_unlock(&data->update_lock);
1331a539d37STomas Pop 
1341a539d37STomas Pop 	return ret == 0 ? data : ERR_PTR(ret);
1351a539d37STomas Pop }
1361a539d37STomas Pop 
1371a539d37STomas Pop static ssize_t temp1_input_show(struct device *dev,
1381a539d37STomas Pop 				struct device_attribute *attr,
1391a539d37STomas Pop 				char *buf)
1401a539d37STomas Pop {
1411a539d37STomas Pop 	struct shtc1_data *data = shtc1_update_client(dev);
1421a539d37STomas Pop 	if (IS_ERR(data))
1431a539d37STomas Pop 		return PTR_ERR(data);
1441a539d37STomas Pop 
1451a539d37STomas Pop 	return sprintf(buf, "%d\n", data->temperature);
1461a539d37STomas Pop }
1471a539d37STomas Pop 
1481a539d37STomas Pop static ssize_t humidity1_input_show(struct device *dev,
1491a539d37STomas Pop 				    struct device_attribute *attr, char *buf)
1501a539d37STomas Pop {
1511a539d37STomas Pop 	struct shtc1_data *data = shtc1_update_client(dev);
1521a539d37STomas Pop 	if (IS_ERR(data))
1531a539d37STomas Pop 		return PTR_ERR(data);
1541a539d37STomas Pop 
1551a539d37STomas Pop 	return sprintf(buf, "%d\n", data->humidity);
1561a539d37STomas Pop }
1571a539d37STomas Pop 
1581a539d37STomas Pop static DEVICE_ATTR_RO(temp1_input);
1591a539d37STomas Pop static DEVICE_ATTR_RO(humidity1_input);
1601a539d37STomas Pop 
1611a539d37STomas Pop static struct attribute *shtc1_attrs[] = {
1621a539d37STomas Pop 	&dev_attr_temp1_input.attr,
1631a539d37STomas Pop 	&dev_attr_humidity1_input.attr,
1641a539d37STomas Pop 	NULL
1651a539d37STomas Pop };
1661a539d37STomas Pop 
1671a539d37STomas Pop ATTRIBUTE_GROUPS(shtc1);
1681a539d37STomas Pop 
1691a539d37STomas Pop static void shtc1_select_command(struct shtc1_data *data)
1701a539d37STomas Pop {
1711a539d37STomas Pop 	if (data->setup.high_precision) {
1721a539d37STomas Pop 		data->command = data->setup.blocking_io ?
1731a539d37STomas Pop 				shtc1_cmd_measure_blocking_hpm :
1741a539d37STomas Pop 				shtc1_cmd_measure_nonblocking_hpm;
175*ffd96868SDan Robertson 		data->nonblocking_wait_time = (data->chip == shtc1) ?
176*ffd96868SDan Robertson 				SHTC1_NONBLOCKING_WAIT_TIME_HPM :
177*ffd96868SDan Robertson 				SHTC3_NONBLOCKING_WAIT_TIME_HPM;
1781a539d37STomas Pop 	} else {
1791a539d37STomas Pop 		data->command = data->setup.blocking_io ?
1801a539d37STomas Pop 				shtc1_cmd_measure_blocking_lpm :
1811a539d37STomas Pop 				shtc1_cmd_measure_nonblocking_lpm;
182*ffd96868SDan Robertson 		data->nonblocking_wait_time = (data->chip == shtc1) ?
183*ffd96868SDan Robertson 				SHTC1_NONBLOCKING_WAIT_TIME_LPM :
184*ffd96868SDan Robertson 				SHTC3_NONBLOCKING_WAIT_TIME_LPM;
1851a539d37STomas Pop 	}
1861a539d37STomas Pop }
1871a539d37STomas Pop 
1881a539d37STomas Pop static int shtc1_probe(struct i2c_client *client,
1891a539d37STomas Pop 		       const struct i2c_device_id *id)
1901a539d37STomas Pop {
1911a539d37STomas Pop 	int ret;
192*ffd96868SDan Robertson 	u16 id_reg;
193*ffd96868SDan Robertson 	char id_reg_buf[2];
1941a539d37STomas Pop 	struct shtc1_data *data;
1951a539d37STomas Pop 	struct device *hwmon_dev;
196*ffd96868SDan Robertson 	enum shtcx_chips chip = id->driver_data;
1971a539d37STomas Pop 	struct i2c_adapter *adap = client->adapter;
1981a539d37STomas Pop 	struct device *dev = &client->dev;
1991a539d37STomas Pop 
2001a539d37STomas Pop 	if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) {
2011a539d37STomas Pop 		dev_err(dev, "plain i2c transactions not supported\n");
2021a539d37STomas Pop 		return -ENODEV;
2031a539d37STomas Pop 	}
2041a539d37STomas Pop 
2051a539d37STomas Pop 	ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH);
2061a539d37STomas Pop 	if (ret != SHTC1_CMD_LENGTH) {
2071a539d37STomas Pop 		dev_err(dev, "could not send read_id_reg command: %d\n", ret);
2081a539d37STomas Pop 		return ret < 0 ? ret : -ENODEV;
2091a539d37STomas Pop 	}
210*ffd96868SDan Robertson 	ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));
211*ffd96868SDan Robertson 	if (ret != sizeof(id_reg_buf)) {
2121a539d37STomas Pop 		dev_err(dev, "could not read ID register: %d\n", ret);
2131a539d37STomas Pop 		return -ENODEV;
2141a539d37STomas Pop 	}
215*ffd96868SDan Robertson 
216*ffd96868SDan Robertson 	id_reg = be16_to_cpup((__be16 *)id_reg_buf);
217*ffd96868SDan Robertson 	if (chip == shtc3) {
218*ffd96868SDan Robertson 		if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) {
219*ffd96868SDan Robertson 			dev_err(dev, "SHTC3 ID register does not match\n");
220*ffd96868SDan Robertson 			return -ENODEV;
221*ffd96868SDan Robertson 		}
222*ffd96868SDan Robertson 	} else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) {
223*ffd96868SDan Robertson 		dev_err(dev, "SHTC1 ID register does not match\n");
2241a539d37STomas Pop 		return -ENODEV;
2251a539d37STomas Pop 	}
2261a539d37STomas Pop 
2271a539d37STomas Pop 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
2281a539d37STomas Pop 	if (!data)
2291a539d37STomas Pop 		return -ENOMEM;
2301a539d37STomas Pop 
2311a539d37STomas Pop 	data->setup.blocking_io = false;
2321a539d37STomas Pop 	data->setup.high_precision = true;
2331a539d37STomas Pop 	data->client = client;
234*ffd96868SDan Robertson 	data->chip = chip;
2351a539d37STomas Pop 
2361a539d37STomas Pop 	if (client->dev.platform_data)
2371a539d37STomas Pop 		data->setup = *(struct shtc1_platform_data *)dev->platform_data;
2381a539d37STomas Pop 	shtc1_select_command(data);
2391a539d37STomas Pop 	mutex_init(&data->update_lock);
2401a539d37STomas Pop 
2411a539d37STomas Pop 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
2421a539d37STomas Pop 							   client->name,
2431a539d37STomas Pop 							   data,
2441a539d37STomas Pop 							   shtc1_groups);
2451a539d37STomas Pop 	if (IS_ERR(hwmon_dev))
2461a539d37STomas Pop 		dev_dbg(dev, "unable to register hwmon device\n");
2471a539d37STomas Pop 
2481a539d37STomas Pop 	return PTR_ERR_OR_ZERO(hwmon_dev);
2491a539d37STomas Pop }
2501a539d37STomas Pop 
2511a539d37STomas Pop /* device ID table */
2521a539d37STomas Pop static const struct i2c_device_id shtc1_id[] = {
253*ffd96868SDan Robertson 	{ "shtc1", shtc1 },
254*ffd96868SDan Robertson 	{ "shtw1", shtc1 },
255*ffd96868SDan Robertson 	{ "shtc3", shtc3 },
2561a539d37STomas Pop 	{ }
2571a539d37STomas Pop };
2581a539d37STomas Pop MODULE_DEVICE_TABLE(i2c, shtc1_id);
2591a539d37STomas Pop 
2601a539d37STomas Pop static struct i2c_driver shtc1_i2c_driver = {
2611a539d37STomas Pop 	.driver.name  = "shtc1",
2621a539d37STomas Pop 	.probe        = shtc1_probe,
2631a539d37STomas Pop 	.id_table     = shtc1_id,
2641a539d37STomas Pop };
2651a539d37STomas Pop 
2661a539d37STomas Pop module_i2c_driver(shtc1_i2c_driver);
2671a539d37STomas Pop 
2681a539d37STomas Pop MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>");
2691a539d37STomas Pop MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver");
2701a539d37STomas Pop MODULE_LICENSE("GPL");
271