289 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/* Sensirion SHTC1 humidity and temperature sensor driver3 *4 * Copyright (C) 2014 Sensirion AG, Switzerland5 * Author: Johannes Winkelmann <johannes.winkelmann@sensirion.com>6 */7 8#include <linux/module.h>9#include <linux/init.h>10#include <linux/slab.h>11#include <linux/i2c.h>12#include <linux/hwmon.h>13#include <linux/hwmon-sysfs.h>14#include <linux/err.h>15#include <linux/delay.h>16#include <linux/platform_data/shtc1.h>17#include <linux/of.h>18 19/* commands (high precision mode) */20static const unsigned char shtc1_cmd_measure_blocking_hpm[] = { 0x7C, 0xA2 };21static const unsigned char shtc1_cmd_measure_nonblocking_hpm[] = { 0x78, 0x66 };22 23/* commands (low precision mode) */24static const unsigned char shtc1_cmd_measure_blocking_lpm[] = { 0x64, 0x58 };25static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };26 27/* command for reading the ID register */28static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 };29 30/*31 * constants for reading the ID register32 * SHTC1: 0x0007 with mask 0x003f33 * SHTW1: 0x0007 with mask 0x003f34 * SHTC3: 0x0807 with mask 0x083f35 */36#define SHTC3_ID 0x080737#define SHTC3_ID_MASK 0x083f38#define SHTC1_ID 0x000739#define SHTC1_ID_MASK 0x003f40 41/* delays for non-blocking i2c commands, both in us */42#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 1440043#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 100044#define SHTC3_NONBLOCKING_WAIT_TIME_HPM 1210045#define SHTC3_NONBLOCKING_WAIT_TIME_LPM 80046 47#define SHTC1_CMD_LENGTH 248#define SHTC1_RESPONSE_LENGTH 649 50enum shtcx_chips {51 shtc1,52 shtc3,53};54 55struct shtc1_data {56 struct i2c_client *client;57 struct mutex update_lock;58 bool valid;59 unsigned long last_updated; /* in jiffies */60 61 const unsigned char *command;62 unsigned int nonblocking_wait_time; /* in us */63 64 struct shtc1_platform_data setup;65 enum shtcx_chips chip;66 67 int temperature; /* 1000 * temperature in dgr C */68 int humidity; /* 1000 * relative humidity in %RH */69};70 71static int shtc1_update_values(struct i2c_client *client,72 struct shtc1_data *data,73 char *buf, int bufsize)74{75 int ret = i2c_master_send(client, data->command, SHTC1_CMD_LENGTH);76 if (ret != SHTC1_CMD_LENGTH) {77 dev_err(&client->dev, "failed to send command: %d\n", ret);78 return ret < 0 ? ret : -EIO;79 }80 81 /*82 * In blocking mode (clock stretching mode) the I2C bus83 * is blocked for other traffic, thus the call to i2c_master_recv()84 * will wait until the data is ready. For non blocking mode, we85 * have to wait ourselves.86 */87 if (!data->setup.blocking_io)88 usleep_range(data->nonblocking_wait_time,89 data->nonblocking_wait_time + 1000);90 91 ret = i2c_master_recv(client, buf, bufsize);92 if (ret != bufsize) {93 dev_err(&client->dev, "failed to read values: %d\n", ret);94 return ret < 0 ? ret : -EIO;95 }96 97 return 0;98}99 100/* sysfs attributes */101static struct shtc1_data *shtc1_update_client(struct device *dev)102{103 struct shtc1_data *data = dev_get_drvdata(dev);104 struct i2c_client *client = data->client;105 unsigned char buf[SHTC1_RESPONSE_LENGTH];106 int val;107 int ret = 0;108 109 mutex_lock(&data->update_lock);110 111 if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) {112 ret = shtc1_update_values(client, data, buf, sizeof(buf));113 if (ret)114 goto out;115 116 /*117 * From datasheet:118 * T = -45 + 175 * ST / 2^16119 * RH = 100 * SRH / 2^16120 *121 * Adapted for integer fixed point (3 digit) arithmetic.122 */123 val = be16_to_cpup((__be16 *)buf);124 data->temperature = ((21875 * val) >> 13) - 45000;125 val = be16_to_cpup((__be16 *)(buf + 3));126 data->humidity = ((12500 * val) >> 13);127 128 data->last_updated = jiffies;129 data->valid = true;130 }131 132out:133 mutex_unlock(&data->update_lock);134 135 return ret == 0 ? data : ERR_PTR(ret);136}137 138static ssize_t temp1_input_show(struct device *dev,139 struct device_attribute *attr,140 char *buf)141{142 struct shtc1_data *data = shtc1_update_client(dev);143 if (IS_ERR(data))144 return PTR_ERR(data);145 146 return sprintf(buf, "%d\n", data->temperature);147}148 149static ssize_t humidity1_input_show(struct device *dev,150 struct device_attribute *attr, char *buf)151{152 struct shtc1_data *data = shtc1_update_client(dev);153 if (IS_ERR(data))154 return PTR_ERR(data);155 156 return sprintf(buf, "%d\n", data->humidity);157}158 159static DEVICE_ATTR_RO(temp1_input);160static DEVICE_ATTR_RO(humidity1_input);161 162static struct attribute *shtc1_attrs[] = {163 &dev_attr_temp1_input.attr,164 &dev_attr_humidity1_input.attr,165 NULL166};167 168ATTRIBUTE_GROUPS(shtc1);169 170static void shtc1_select_command(struct shtc1_data *data)171{172 if (data->setup.high_precision) {173 data->command = data->setup.blocking_io ?174 shtc1_cmd_measure_blocking_hpm :175 shtc1_cmd_measure_nonblocking_hpm;176 data->nonblocking_wait_time = (data->chip == shtc1) ?177 SHTC1_NONBLOCKING_WAIT_TIME_HPM :178 SHTC3_NONBLOCKING_WAIT_TIME_HPM;179 } else {180 data->command = data->setup.blocking_io ?181 shtc1_cmd_measure_blocking_lpm :182 shtc1_cmd_measure_nonblocking_lpm;183 data->nonblocking_wait_time = (data->chip == shtc1) ?184 SHTC1_NONBLOCKING_WAIT_TIME_LPM :185 SHTC3_NONBLOCKING_WAIT_TIME_LPM;186 }187}188 189static int shtc1_probe(struct i2c_client *client)190{191 int ret;192 u16 id_reg;193 char id_reg_buf[2];194 struct shtc1_data *data;195 struct device *hwmon_dev;196 enum shtcx_chips chip = (uintptr_t)i2c_get_match_data(client);197 struct i2c_adapter *adap = client->adapter;198 struct device *dev = &client->dev;199 struct device_node *np = dev->of_node;200 201 if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) {202 dev_err(dev, "plain i2c transactions not supported\n");203 return -ENODEV;204 }205 206 ret = i2c_master_send(client, shtc1_cmd_read_id_reg, SHTC1_CMD_LENGTH);207 if (ret != SHTC1_CMD_LENGTH) {208 dev_err(dev, "could not send read_id_reg command: %d\n", ret);209 return ret < 0 ? ret : -ENODEV;210 }211 ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));212 if (ret != sizeof(id_reg_buf)) {213 dev_err(dev, "could not read ID register: %d\n", ret);214 return -ENODEV;215 }216 217 id_reg = be16_to_cpup((__be16 *)id_reg_buf);218 if (chip == shtc3) {219 if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) {220 dev_err(dev, "SHTC3 ID register does not match\n");221 return -ENODEV;222 }223 } else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) {224 dev_err(dev, "SHTC1 ID register does not match\n");225 return -ENODEV;226 }227 228 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);229 if (!data)230 return -ENOMEM;231 232 data->setup.blocking_io = false;233 data->setup.high_precision = true;234 data->client = client;235 data->chip = chip;236 237 if (np) {238 data->setup.blocking_io = of_property_read_bool(np, "sensirion,blocking-io");239 data->setup.high_precision = !of_property_read_bool(np, "sensirion,low-precision");240 } else {241 if (client->dev.platform_data)242 data->setup = *(struct shtc1_platform_data *)dev->platform_data;243 }244 245 shtc1_select_command(data);246 mutex_init(&data->update_lock);247 248 hwmon_dev = devm_hwmon_device_register_with_groups(dev,249 client->name,250 data,251 shtc1_groups);252 if (IS_ERR(hwmon_dev))253 dev_dbg(dev, "unable to register hwmon device\n");254 255 return PTR_ERR_OR_ZERO(hwmon_dev);256}257 258/* device ID table */259static const struct i2c_device_id shtc1_id[] = {260 { "shtc1", shtc1 },261 { "shtw1", shtc1 },262 { "shtc3", shtc3 },263 { }264};265MODULE_DEVICE_TABLE(i2c, shtc1_id);266 267static const struct of_device_id shtc1_of_match[] = {268 { .compatible = "sensirion,shtc1" },269 { .compatible = "sensirion,shtw1" },270 { .compatible = "sensirion,shtc3" },271 { }272};273MODULE_DEVICE_TABLE(of, shtc1_of_match);274 275static struct i2c_driver shtc1_i2c_driver = {276 .driver = {277 .name = "shtc1",278 .of_match_table = shtc1_of_match,279 },280 .probe = shtc1_probe,281 .id_table = shtc1_id,282};283 284module_i2c_driver(shtc1_i2c_driver);285 286MODULE_AUTHOR("Johannes Winkelmann <johannes.winkelmann@sensirion.com>");287MODULE_DESCRIPTION("Sensirion SHTC1 humidity and temperature sensor driver");288MODULE_LICENSE("GPL");289