162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Sensirion SHTC1 humidity and temperature sensor driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2014 Sensirion AG, Switzerland 562306a36Sopenharmony_ci * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/hwmon.h> 1362306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/platform_data/shtc1.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* commands (high precision mode) */ 2062306a36Sopenharmony_cistatic const unsigned char shtc1_cmd_measure_blocking_hpm[] = { 0x7C, 0xA2 }; 2162306a36Sopenharmony_cistatic const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 }; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* commands (low precision mode) */ 2462306a36Sopenharmony_cistatic const unsigned char shtc1_cmd_measure_blocking_lpm[] = { 0x64, 0x58 }; 2562306a36Sopenharmony_cistatic const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c }; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* command for reading the ID register */ 2862306a36Sopenharmony_cistatic const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * constants for reading the ID register 3262306a36Sopenharmony_ci * SHTC1: 0x0007 with mask 0x003f 3362306a36Sopenharmony_ci * SHTW1: 0x0007 with mask 0x003f 3462306a36Sopenharmony_ci * SHTC3: 0x0807 with mask 0x083f 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci#define SHTC3_ID 0x0807 3762306a36Sopenharmony_ci#define SHTC3_ID_MASK 0x083f 3862306a36Sopenharmony_ci#define SHTC1_ID 0x0007 3962306a36Sopenharmony_ci#define SHTC1_ID_MASK 0x003f 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* delays for non-blocking i2c commands, both in us */ 4262306a36Sopenharmony_ci#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 4362306a36Sopenharmony_ci#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1000 4462306a36Sopenharmony_ci#define SHTC3_NONBLOCKING_WAIT_TIME_HPM 12100 4562306a36Sopenharmony_ci#define SHTC3_NONBLOCKING_WAIT_TIME_LPM 800 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define SHTC1_CMD_LENGTH 2 4862306a36Sopenharmony_ci#define SHTC1_RESPONSE_LENGTH 6 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cienum shtcx_chips { 5162306a36Sopenharmony_ci shtc1, 5262306a36Sopenharmony_ci shtc3, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct shtc1_data { 5662306a36Sopenharmony_ci struct i2c_client *client; 5762306a36Sopenharmony_ci struct mutex update_lock; 5862306a36Sopenharmony_ci bool valid; 5962306a36Sopenharmony_ci unsigned long last_updated; /* in jiffies */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci const unsigned char *command; 6262306a36Sopenharmony_ci unsigned int nonblocking_wait_time; /* in us */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci struct shtc1_platform_data setup; 6562306a36Sopenharmony_ci enum shtcx_chips chip; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci int temperature; /* 1000 * temperature in dgr C */ 6862306a36Sopenharmony_ci int humidity; /* 1000 * relative humidity in %RH */ 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int shtc1_update_values(struct i2c_client *client, 7262306a36Sopenharmony_ci struct shtc1_data *data, 7362306a36Sopenharmony_ci char *buf, int bufsize) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH); 7662306a36Sopenharmony_ci if (ret != SHTC1_CMD_LENGTH) { 7762306a36Sopenharmony_ci dev_err(&client->dev, "failed to send command: %d\n", ret); 7862306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * In blocking mode (clock stretching mode) the I2C bus 8362306a36Sopenharmony_ci * is blocked for other traffic, thus the call to i2c_master_recv() 8462306a36Sopenharmony_ci * will wait until the data is ready. For non blocking mode, we 8562306a36Sopenharmony_ci * have to wait ourselves. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci if (!data->setup.blocking_io) 8862306a36Sopenharmony_ci usleep_range(data->nonblocking_wait_time, 8962306a36Sopenharmony_ci data->nonblocking_wait_time + 1000); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci ret = i2c_master_recv(client, buf, bufsize); 9262306a36Sopenharmony_ci if (ret != bufsize) { 9362306a36Sopenharmony_ci dev_err(&client->dev, "failed to read values: %d\n", ret); 9462306a36Sopenharmony_ci return ret < 0 ? ret : -EIO; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* sysfs attributes */ 10162306a36Sopenharmony_cistatic struct shtc1_data *shtc1_update_client(struct device *dev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct shtc1_data *data = dev_get_drvdata(dev); 10462306a36Sopenharmony_ci struct i2c_client *client = data->client; 10562306a36Sopenharmony_ci unsigned char buf[SHTC1_RESPONSE_LENGTH]; 10662306a36Sopenharmony_ci int val; 10762306a36Sopenharmony_ci int ret = 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) { 11262306a36Sopenharmony_ci ret = shtc1_update_values(client, data, buf, sizeof(buf)); 11362306a36Sopenharmony_ci if (ret) 11462306a36Sopenharmony_ci goto out; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * From datasheet: 11862306a36Sopenharmony_ci * T = -45 + 175 * ST / 2^16 11962306a36Sopenharmony_ci * RH = 100 * SRH / 2^16 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Adapted for integer fixed point (3 digit) arithmetic. 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci val = be16_to_cpup((__be16 *)buf); 12462306a36Sopenharmony_ci data->temperature = ((21875 * val) >> 13) - 45000; 12562306a36Sopenharmony_ci val = be16_to_cpup((__be16 *)(buf + 3)); 12662306a36Sopenharmony_ci data->humidity = ((12500 * val) >> 13); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci data->last_updated = jiffies; 12962306a36Sopenharmony_ci data->valid = true; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciout: 13362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return ret == 0 ? data : ERR_PTR(ret); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic ssize_t temp1_input_show(struct device *dev, 13962306a36Sopenharmony_ci struct device_attribute *attr, 14062306a36Sopenharmony_ci char *buf) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct shtc1_data *data = shtc1_update_client(dev); 14362306a36Sopenharmony_ci if (IS_ERR(data)) 14462306a36Sopenharmony_ci return PTR_ERR(data); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->temperature); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic ssize_t humidity1_input_show(struct device *dev, 15062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct shtc1_data *data = shtc1_update_client(dev); 15362306a36Sopenharmony_ci if (IS_ERR(data)) 15462306a36Sopenharmony_ci return PTR_ERR(data); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return sprintf(buf, "%d\n", data->humidity); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(temp1_input); 16062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(humidity1_input); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct attribute *shtc1_attrs[] = { 16362306a36Sopenharmony_ci &dev_attr_temp1_input.attr, 16462306a36Sopenharmony_ci &dev_attr_humidity1_input.attr, 16562306a36Sopenharmony_ci NULL 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciATTRIBUTE_GROUPS(shtc1); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void shtc1_select_command(struct shtc1_data *data) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci if (data->setup.high_precision) { 17362306a36Sopenharmony_ci data->command = data->setup.blocking_io ? 17462306a36Sopenharmony_ci shtc1_cmd_measure_blocking_hpm : 17562306a36Sopenharmony_ci shtc1_cmd_measure_nonblocking_hpm; 17662306a36Sopenharmony_ci data->nonblocking_wait_time = (data->chip == shtc1) ? 17762306a36Sopenharmony_ci SHTC1_NONBLOCKING_WAIT_TIME_HPM : 17862306a36Sopenharmony_ci SHTC3_NONBLOCKING_WAIT_TIME_HPM; 17962306a36Sopenharmony_ci } else { 18062306a36Sopenharmony_ci data->command = data->setup.blocking_io ? 18162306a36Sopenharmony_ci shtc1_cmd_measure_blocking_lpm : 18262306a36Sopenharmony_ci shtc1_cmd_measure_nonblocking_lpm; 18362306a36Sopenharmony_ci data->nonblocking_wait_time = (data->chip == shtc1) ? 18462306a36Sopenharmony_ci SHTC1_NONBLOCKING_WAIT_TIME_LPM : 18562306a36Sopenharmony_ci SHTC3_NONBLOCKING_WAIT_TIME_LPM; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic const struct i2c_device_id shtc1_id[]; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int shtc1_probe(struct i2c_client *client) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci int ret; 19462306a36Sopenharmony_ci u16 id_reg; 19562306a36Sopenharmony_ci char id_reg_buf[2]; 19662306a36Sopenharmony_ci struct shtc1_data *data; 19762306a36Sopenharmony_ci struct device *hwmon_dev; 19862306a36Sopenharmony_ci enum shtcx_chips chip = i2c_match_id(shtc1_id, client)->driver_data; 19962306a36Sopenharmony_ci struct i2c_adapter *adap = client->adapter; 20062306a36Sopenharmony_ci struct device *dev = &client->dev; 20162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) { 20462306a36Sopenharmony_ci dev_err(dev, "plain i2c transactions not supported\n"); 20562306a36Sopenharmony_ci return -ENODEV; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH); 20962306a36Sopenharmony_ci if (ret != SHTC1_CMD_LENGTH) { 21062306a36Sopenharmony_ci dev_err(dev, "could not send read_id_reg command: %d\n", ret); 21162306a36Sopenharmony_ci return ret < 0 ? ret : -ENODEV; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf)); 21462306a36Sopenharmony_ci if (ret != sizeof(id_reg_buf)) { 21562306a36Sopenharmony_ci dev_err(dev, "could not read ID register: %d\n", ret); 21662306a36Sopenharmony_ci return -ENODEV; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci id_reg = be16_to_cpup((__be16 *)id_reg_buf); 22062306a36Sopenharmony_ci if (chip == shtc3) { 22162306a36Sopenharmony_ci if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) { 22262306a36Sopenharmony_ci dev_err(dev, "SHTC3 ID register does not match\n"); 22362306a36Sopenharmony_ci return -ENODEV; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) { 22662306a36Sopenharmony_ci dev_err(dev, "SHTC1 ID register does not match\n"); 22762306a36Sopenharmony_ci return -ENODEV; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 23162306a36Sopenharmony_ci if (!data) 23262306a36Sopenharmony_ci return -ENOMEM; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci data->setup.blocking_io = false; 23562306a36Sopenharmony_ci data->setup.high_precision = true; 23662306a36Sopenharmony_ci data->client = client; 23762306a36Sopenharmony_ci data->chip = chip; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (np) { 24062306a36Sopenharmony_ci data->setup.blocking_io = of_property_read_bool(np, "sensirion,blocking-io"); 24162306a36Sopenharmony_ci data->setup.high_precision = !of_property_read_bool(np, "sensicon,low-precision"); 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci if (client->dev.platform_data) 24462306a36Sopenharmony_ci data->setup = *(struct shtc1_platform_data *)dev->platform_data; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci shtc1_select_command(data); 24862306a36Sopenharmony_ci mutex_init(&data->update_lock); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(dev, 25162306a36Sopenharmony_ci client->name, 25262306a36Sopenharmony_ci data, 25362306a36Sopenharmony_ci shtc1_groups); 25462306a36Sopenharmony_ci if (IS_ERR(hwmon_dev)) 25562306a36Sopenharmony_ci dev_dbg(dev, "unable to register hwmon device\n"); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* device ID table */ 26162306a36Sopenharmony_cistatic const struct i2c_device_id shtc1_id[] = { 26262306a36Sopenharmony_ci { "shtc1", shtc1 }, 26362306a36Sopenharmony_ci { "shtw1", shtc1 }, 26462306a36Sopenharmony_ci { "shtc3", shtc3 }, 26562306a36Sopenharmony_ci { } 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, shtc1_id); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic const struct of_device_id shtc1_of_match[] = { 27062306a36Sopenharmony_ci { .compatible = "sensirion,shtc1" }, 27162306a36Sopenharmony_ci { .compatible = "sensirion,shtw1" }, 27262306a36Sopenharmony_ci { .compatible = "sensirion,shtc3" }, 27362306a36Sopenharmony_ci { } 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, shtc1_of_match); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic struct i2c_driver shtc1_i2c_driver = { 27862306a36Sopenharmony_ci .driver = { 27962306a36Sopenharmony_ci .name = "shtc1", 28062306a36Sopenharmony_ci .of_match_table = shtc1_of_match, 28162306a36Sopenharmony_ci }, 28262306a36Sopenharmony_ci .probe = shtc1_probe, 28362306a36Sopenharmony_ci .id_table = shtc1_id, 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cimodule_i2c_driver(shtc1_i2c_driver); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ciMODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>"); 28962306a36Sopenharmony_ciMODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver"); 29062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 291