brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 0797ece Raw
191 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * si7005.c - Support for Silabs Si7005 humidity and temperature sensor4 *5 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>6 *7 * (7-bit I2C slave address 0x40)8 *9 * TODO: heater, fast mode, processed mode (temp. / linearity compensation)10 */11 12#include <linux/err.h>13#include <linux/i2c.h>14#include <linux/delay.h>15#include <linux/module.h>16#include <linux/pm.h>17 18#include <linux/iio/iio.h>19#include <linux/iio/sysfs.h>20 21#define SI7005_STATUS 0x0022#define SI7005_DATA 0x01 /* 16-bit, MSB */23#define SI7005_CONFIG 0x0324#define SI7005_ID 0x1125 26#define SI7005_STATUS_NRDY BIT(0)27#define SI7005_CONFIG_TEMP BIT(4)28#define SI7005_CONFIG_START BIT(0)29 30#define SI7005_ID_7005 0x5031#define SI7005_ID_7015 0xf032 33struct si7005_data {34	struct i2c_client *client;35	struct mutex lock;36	u8 config;37};38 39static int si7005_read_measurement(struct si7005_data *data, bool temp)40{41	int tries = 50;42	int ret;43 44	mutex_lock(&data->lock);45 46	ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG,47		data->config | SI7005_CONFIG_START |48		(temp ? SI7005_CONFIG_TEMP : 0));49	if (ret < 0)50		goto done;51 52	while (tries-- > 0) {53		msleep(20);54		ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS);55		if (ret < 0)56			goto done;57		if (!(ret & SI7005_STATUS_NRDY))58			break;59	}60	if (tries < 0) {61		ret = -EIO;62		goto done;63	}64 65	ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA);66 67done:68	mutex_unlock(&data->lock);69 70	return ret;71}72 73static int si7005_read_raw(struct iio_dev *indio_dev,74			    struct iio_chan_spec const *chan, int *val,75			    int *val2, long mask)76{77	struct si7005_data *data = iio_priv(indio_dev);78	int ret;79 80	switch (mask) {81	case IIO_CHAN_INFO_RAW:82		ret = si7005_read_measurement(data, chan->type == IIO_TEMP);83		if (ret < 0)84			return ret;85		*val = ret;86		return IIO_VAL_INT;87	case IIO_CHAN_INFO_SCALE:88		if (chan->type == IIO_TEMP) {89			*val = 7;90			*val2 = 812500;91		} else {92			*val = 3;93			*val2 = 906250;94		}95		return IIO_VAL_INT_PLUS_MICRO;96	case IIO_CHAN_INFO_OFFSET:97		if (chan->type == IIO_TEMP)98			*val = -50 * 32 * 4;99		else100			*val = -24 * 16 * 16;101		return IIO_VAL_INT;102	default:103		break;104	}105 106	return -EINVAL;107}108 109static const struct iio_chan_spec si7005_channels[] = {110	{111		.type = IIO_HUMIDITYRELATIVE,112		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |113			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),114	},115	{116		.type = IIO_TEMP,117		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |118			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),119	}120};121 122static const struct iio_info si7005_info = {123	.read_raw = si7005_read_raw,124};125 126static int si7005_probe(struct i2c_client *client)127{128	struct iio_dev *indio_dev;129	struct si7005_data *data;130	int ret;131 132	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))133		return -EOPNOTSUPP;134 135	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));136	if (!indio_dev)137		return -ENOMEM;138 139	data = iio_priv(indio_dev);140	i2c_set_clientdata(client, indio_dev);141	data->client = client;142	mutex_init(&data->lock);143 144	indio_dev->name = dev_name(&client->dev);145	indio_dev->modes = INDIO_DIRECT_MODE;146	indio_dev->info = &si7005_info;147 148	indio_dev->channels = si7005_channels;149	indio_dev->num_channels = ARRAY_SIZE(si7005_channels);150 151	ret = i2c_smbus_read_byte_data(client, SI7005_ID);152	if (ret < 0)153		return ret;154	if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015)155		return -ENODEV;156 157	ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG);158	if (ret < 0)159		return ret;160	data->config = ret;161 162	return devm_iio_device_register(&client->dev, indio_dev);163}164 165static const struct i2c_device_id si7005_id[] = {166	{ "si7005" },167	{ "th02" },168	{ }169};170MODULE_DEVICE_TABLE(i2c, si7005_id);171 172static const struct of_device_id si7005_dt_ids[] = {173	{ .compatible = "silabs,si7005" },174	{ }175};176MODULE_DEVICE_TABLE(of, si7005_dt_ids);177 178static struct i2c_driver si7005_driver = {179	.driver = {180		.name	= "si7005",181		.of_match_table = si7005_dt_ids,182	},183	.probe = si7005_probe,184	.id_table = si7005_id,185};186module_i2c_driver(si7005_driver);187 188MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");189MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver");190MODULE_LICENSE("GPL");191