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