xref: /openbmc/linux/drivers/hwmon/shtc1.c (revision c942fddf8793b2013be8c901b47d0a8dc02bf99f)
1*c942fddfSThomas 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 
291a539d37STomas Pop /* constants for reading the ID register */
301a539d37STomas Pop #define SHTC1_ID	  0x07
311a539d37STomas Pop #define SHTC1_ID_REG_MASK 0x1f
321a539d37STomas Pop 
331a539d37STomas Pop /* delays for non-blocking i2c commands, both in us */
341a539d37STomas Pop #define SHTC1_NONBLOCKING_WAIT_TIME_HPM  14400
351a539d37STomas Pop #define SHTC1_NONBLOCKING_WAIT_TIME_LPM   1000
361a539d37STomas Pop 
371a539d37STomas Pop #define SHTC1_CMD_LENGTH      2
381a539d37STomas Pop #define SHTC1_RESPONSE_LENGTH 6
391a539d37STomas Pop 
401a539d37STomas Pop struct shtc1_data {
411a539d37STomas Pop 	struct i2c_client *client;
421a539d37STomas Pop 	struct mutex update_lock;
431a539d37STomas Pop 	bool valid;
441a539d37STomas Pop 	unsigned long last_updated; /* in jiffies */
451a539d37STomas Pop 
461a539d37STomas Pop 	const unsigned char *command;
471a539d37STomas Pop 	unsigned int nonblocking_wait_time; /* in us */
481a539d37STomas Pop 
491a539d37STomas Pop 	struct shtc1_platform_data setup;
501a539d37STomas Pop 
511a539d37STomas Pop 	int temperature; /* 1000 * temperature in dgr C */
521a539d37STomas Pop 	int humidity; /* 1000 * relative humidity in %RH */
531a539d37STomas Pop };
541a539d37STomas Pop 
551a539d37STomas Pop static int shtc1_update_values(struct i2c_client *client,
561a539d37STomas Pop 			       struct shtc1_data *data,
571a539d37STomas Pop 			       char *buf, int bufsize)
581a539d37STomas Pop {
591a539d37STomas Pop 	int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH);
601a539d37STomas Pop 	if (ret != SHTC1_CMD_LENGTH) {
611a539d37STomas Pop 		dev_err(&client->dev, "failed to send command: %d\n", ret);
621a539d37STomas Pop 		return ret < 0 ? ret : -EIO;
631a539d37STomas Pop 	}
641a539d37STomas Pop 
651a539d37STomas Pop 	/*
661a539d37STomas Pop 	 * In blocking mode (clock stretching mode) the I2C bus
671a539d37STomas Pop 	 * is blocked for other traffic, thus the call to i2c_master_recv()
681a539d37STomas Pop 	 * will wait until the data is ready. For non blocking mode, we
691a539d37STomas Pop 	 * have to wait ourselves.
701a539d37STomas Pop 	 */
711a539d37STomas Pop 	if (!data->setup.blocking_io)
721a539d37STomas Pop 		usleep_range(data->nonblocking_wait_time,
731a539d37STomas Pop 			     data->nonblocking_wait_time + 1000);
741a539d37STomas Pop 
751a539d37STomas Pop 	ret = i2c_master_recv(client, buf, bufsize);
761a539d37STomas Pop 	if (ret != bufsize) {
771a539d37STomas Pop 		dev_err(&client->dev, "failed to read values: %d\n", ret);
781a539d37STomas Pop 		return ret < 0 ? ret : -EIO;
791a539d37STomas Pop 	}
801a539d37STomas Pop 
811a539d37STomas Pop 	return 0;
821a539d37STomas Pop }
831a539d37STomas Pop 
841a539d37STomas Pop /* sysfs attributes */
851a539d37STomas Pop static struct shtc1_data *shtc1_update_client(struct device *dev)
861a539d37STomas Pop {
871a539d37STomas Pop 	struct shtc1_data *data = dev_get_drvdata(dev);
881a539d37STomas Pop 	struct i2c_client *client = data->client;
891a539d37STomas Pop 	unsigned char buf[SHTC1_RESPONSE_LENGTH];
901a539d37STomas Pop 	int val;
911a539d37STomas Pop 	int ret = 0;
921a539d37STomas Pop 
931a539d37STomas Pop 	mutex_lock(&data->update_lock);
941a539d37STomas Pop 
951a539d37STomas Pop 	if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {
961a539d37STomas Pop 		ret = shtc1_update_values(client, data, buf, sizeof(buf));
971a539d37STomas Pop 		if (ret)
981a539d37STomas Pop 			goto out;
991a539d37STomas Pop 
1001a539d37STomas Pop 		/*
1011a539d37STomas Pop 		 * From datasheet:
1021a539d37STomas Pop 		 * T = -45 + 175 * ST / 2^16
1031a539d37STomas Pop 		 * RH = 100 * SRH / 2^16
1041a539d37STomas Pop 		 *
1051a539d37STomas Pop 		 * Adapted for integer fixed point (3 digit) arithmetic.
1061a539d37STomas Pop 		 */
1071a539d37STomas Pop 		val = be16_to_cpup((__be16 *)buf);
1081a539d37STomas Pop 		data->temperature = ((21875 * val) >> 13) - 45000;
1091a539d37STomas Pop 		val = be16_to_cpup((__be16 *)(buf + 3));
1101a539d37STomas Pop 		data->humidity = ((12500 * val) >> 13);
1111a539d37STomas Pop 
1121a539d37STomas Pop 		data->last_updated = jiffies;
1131a539d37STomas Pop 		data->valid = true;
1141a539d37STomas Pop 	}
1151a539d37STomas Pop 
1161a539d37STomas Pop out:
1171a539d37STomas Pop 	mutex_unlock(&data->update_lock);
1181a539d37STomas Pop 
1191a539d37STomas Pop 	return ret == 0 ? data : ERR_PTR(ret);
1201a539d37STomas Pop }
1211a539d37STomas Pop 
1221a539d37STomas Pop static ssize_t temp1_input_show(struct device *dev,
1231a539d37STomas Pop 				struct device_attribute *attr,
1241a539d37STomas Pop 				char *buf)
1251a539d37STomas Pop {
1261a539d37STomas Pop 	struct shtc1_data *data = shtc1_update_client(dev);
1271a539d37STomas Pop 	if (IS_ERR(data))
1281a539d37STomas Pop 		return PTR_ERR(data);
1291a539d37STomas Pop 
1301a539d37STomas Pop 	return sprintf(buf, "%d\n", data->temperature);
1311a539d37STomas Pop }
1321a539d37STomas Pop 
1331a539d37STomas Pop static ssize_t humidity1_input_show(struct device *dev,
1341a539d37STomas Pop 				    struct device_attribute *attr, char *buf)
1351a539d37STomas Pop {
1361a539d37STomas Pop 	struct shtc1_data *data = shtc1_update_client(dev);
1371a539d37STomas Pop 	if (IS_ERR(data))
1381a539d37STomas Pop 		return PTR_ERR(data);
1391a539d37STomas Pop 
1401a539d37STomas Pop 	return sprintf(buf, "%d\n", data->humidity);
1411a539d37STomas Pop }
1421a539d37STomas Pop 
1431a539d37STomas Pop static DEVICE_ATTR_RO(temp1_input);
1441a539d37STomas Pop static DEVICE_ATTR_RO(humidity1_input);
1451a539d37STomas Pop 
1461a539d37STomas Pop static struct attribute *shtc1_attrs[] = {
1471a539d37STomas Pop 	&dev_attr_temp1_input.attr,
1481a539d37STomas Pop 	&dev_attr_humidity1_input.attr,
1491a539d37STomas Pop 	NULL
1501a539d37STomas Pop };
1511a539d37STomas Pop 
1521a539d37STomas Pop ATTRIBUTE_GROUPS(shtc1);
1531a539d37STomas Pop 
1541a539d37STomas Pop static void shtc1_select_command(struct shtc1_data *data)
1551a539d37STomas Pop {
1561a539d37STomas Pop 	if (data->setup.high_precision) {
1571a539d37STomas Pop 		data->command = data->setup.blocking_io ?
1581a539d37STomas Pop 				shtc1_cmd_measure_blocking_hpm :
1591a539d37STomas Pop 				shtc1_cmd_measure_nonblocking_hpm;
1601a539d37STomas Pop 		data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM;
1611a539d37STomas Pop 
1621a539d37STomas Pop 	} else {
1631a539d37STomas Pop 		data->command = data->setup.blocking_io ?
1641a539d37STomas Pop 				shtc1_cmd_measure_blocking_lpm :
1651a539d37STomas Pop 				shtc1_cmd_measure_nonblocking_lpm;
1661a539d37STomas Pop 		data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM;
1671a539d37STomas Pop 	}
1681a539d37STomas Pop }
1691a539d37STomas Pop 
1701a539d37STomas Pop static int shtc1_probe(struct i2c_client *client,
1711a539d37STomas Pop 		       const struct i2c_device_id *id)
1721a539d37STomas Pop {
1731a539d37STomas Pop 	int ret;
1741a539d37STomas Pop 	char id_reg[2];
1751a539d37STomas Pop 	struct shtc1_data *data;
1761a539d37STomas Pop 	struct device *hwmon_dev;
1771a539d37STomas Pop 	struct i2c_adapter *adap = client->adapter;
1781a539d37STomas Pop 	struct device *dev = &client->dev;
1791a539d37STomas Pop 
1801a539d37STomas Pop 	if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) {
1811a539d37STomas Pop 		dev_err(dev, "plain i2c transactions not supported\n");
1821a539d37STomas Pop 		return -ENODEV;
1831a539d37STomas Pop 	}
1841a539d37STomas Pop 
1851a539d37STomas Pop 	ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH);
1861a539d37STomas Pop 	if (ret != SHTC1_CMD_LENGTH) {
1871a539d37STomas Pop 		dev_err(dev, "could not send read_id_reg command: %d\n", ret);
1881a539d37STomas Pop 		return ret < 0 ? ret : -ENODEV;
1891a539d37STomas Pop 	}
1901a539d37STomas Pop 	ret = i2c_master_recv(client, id_reg, sizeof(id_reg));
1911a539d37STomas Pop 	if (ret != sizeof(id_reg)) {
1921a539d37STomas Pop 		dev_err(dev, "could not read ID register: %d\n", ret);
1931a539d37STomas Pop 		return -ENODEV;
1941a539d37STomas Pop 	}
1951a539d37STomas Pop 	if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) {
1961a539d37STomas Pop 		dev_err(dev, "ID register doesn't match\n");
1971a539d37STomas Pop 		return -ENODEV;
1981a539d37STomas Pop 	}
1991a539d37STomas Pop 
2001a539d37STomas Pop 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
2011a539d37STomas Pop 	if (!data)
2021a539d37STomas Pop 		return -ENOMEM;
2031a539d37STomas Pop 
2041a539d37STomas Pop 	data->setup.blocking_io = false;
2051a539d37STomas Pop 	data->setup.high_precision = true;
2061a539d37STomas Pop 	data->client = client;
2071a539d37STomas Pop 
2081a539d37STomas Pop 	if (client->dev.platform_data)
2091a539d37STomas Pop 		data->setup = *(struct shtc1_platform_data *)dev->platform_data;
2101a539d37STomas Pop 	shtc1_select_command(data);
2111a539d37STomas Pop 	mutex_init(&data->update_lock);
2121a539d37STomas Pop 
2131a539d37STomas Pop 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
2141a539d37STomas Pop 							   client->name,
2151a539d37STomas Pop 							   data,
2161a539d37STomas Pop 							   shtc1_groups);
2171a539d37STomas Pop 	if (IS_ERR(hwmon_dev))
2181a539d37STomas Pop 		dev_dbg(dev, "unable to register hwmon device\n");
2191a539d37STomas Pop 
2201a539d37STomas Pop 	return PTR_ERR_OR_ZERO(hwmon_dev);
2211a539d37STomas Pop }
2221a539d37STomas Pop 
2231a539d37STomas Pop /* device ID table */
2241a539d37STomas Pop static const struct i2c_device_id shtc1_id[] = {
2251a539d37STomas Pop 	{ "shtc1", 0 },
2261a539d37STomas Pop 	{ "shtw1", 0 },
2271a539d37STomas Pop 	{ }
2281a539d37STomas Pop };
2291a539d37STomas Pop MODULE_DEVICE_TABLE(i2c, shtc1_id);
2301a539d37STomas Pop 
2311a539d37STomas Pop static struct i2c_driver shtc1_i2c_driver = {
2321a539d37STomas Pop 	.driver.name  = "shtc1",
2331a539d37STomas Pop 	.probe        = shtc1_probe,
2341a539d37STomas Pop 	.id_table     = shtc1_id,
2351a539d37STomas Pop };
2361a539d37STomas Pop 
2371a539d37STomas Pop module_i2c_driver(shtc1_i2c_driver);
2381a539d37STomas Pop 
2391a539d37STomas Pop MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>");
2401a539d37STomas Pop MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver");
2411a539d37STomas Pop MODULE_LICENSE("GPL");
242