brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 2ac906e Raw
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