File Index
Files and directories
Sign in
FILE

max30208.c

File preview with syntax highlighting.

linux-6.19.14/drivers/iio/temperature/max30208.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3/*
  4 * Copyright (c) Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
  5 *
  6 * Maxim MAX30208 digital temperature sensor with 0.1°C accuracy
  7 * (7-bit I2C slave address (0x50 - 0x53))
  8 */
  9
 10#include <linux/bitops.h>
 11#include <linux/delay.h>
 12#include <linux/iio/iio.h>
 13#include <linux/i2c.h>
 14#include <linux/module.h>
 15#include <linux/types.h>
 16
 17#define MAX30208_STATUS			0x00
 18#define MAX30208_STATUS_TEMP_RDY	BIT(0)
 19#define MAX30208_INT_ENABLE		0x01
 20#define MAX30208_INT_ENABLE_TEMP_RDY	BIT(0)
 21
 22#define MAX30208_FIFO_OVF_CNTR		0x06
 23#define MAX30208_FIFO_DATA_CNTR		0x07
 24#define MAX30208_FIFO_DATA		0x08
 25
 26#define MAX30208_FIFO_CONFIG		0x0a
 27#define MAX30208_FIFO_CONFIG_RO		BIT(1)
 28
 29#define MAX30208_SYSTEM_CTRL		0x0c
 30#define MAX30208_SYSTEM_CTRL_RESET	0x01
 31
 32#define MAX30208_TEMP_SENSOR_SETUP	0x14
 33#define MAX30208_TEMP_SENSOR_SETUP_CONV	BIT(0)
 34
 35struct max30208_data {
 36	struct i2c_client *client;
 37	struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
 38};
 39
 40static const struct iio_chan_spec max30208_channels[] = {
 41	{
 42		.type = IIO_TEMP,
 43		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
 44	},
 45};
 46
 47/**
 48 * max30208_request() - Request a reading
 49 * @data: Struct comprising member elements of the device
 50 *
 51 * Requests a reading from the device and waits until the conversion is ready.
 52 */
 53static int max30208_request(struct max30208_data *data)
 54{
 55	/*
 56	 * Sensor can take up to 500 ms to respond so execute a total of
 57	 * 10 retries to give the device sufficient time.
 58	 */
 59	int retries = 10;
 60	u8 regval;
 61	int ret;
 62
 63	ret = i2c_smbus_read_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP);
 64	if (ret < 0)
 65		return ret;
 66
 67	regval = ret | MAX30208_TEMP_SENSOR_SETUP_CONV;
 68
 69	ret = i2c_smbus_write_byte_data(data->client, MAX30208_TEMP_SENSOR_SETUP, regval);
 70	if (ret)
 71		return ret;
 72
 73	while (retries--) {
 74		ret = i2c_smbus_read_byte_data(data->client, MAX30208_STATUS);
 75		if (ret < 0)
 76			return ret;
 77
 78		if (ret & MAX30208_STATUS_TEMP_RDY)
 79			return 0;
 80
 81		msleep(50);
 82	}
 83	dev_err(&data->client->dev, "Temperature conversion failed\n");
 84
 85	return -ETIMEDOUT;
 86}
 87
 88static int max30208_update_temp(struct max30208_data *data)
 89{
 90	u8 data_count;
 91	int ret;
 92
 93	mutex_lock(&data->lock);
 94
 95	ret = max30208_request(data);
 96	if (ret)
 97		goto unlock;
 98
 99	ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_OVF_CNTR);
100	if (ret < 0)
101		goto unlock;
102	else if (!ret) {
103		ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_DATA_CNTR);
104		if (ret < 0)
105			goto unlock;
106
107		data_count = ret;
108	} else
109		data_count = 1;
110
111	while (data_count) {
112		ret = i2c_smbus_read_word_swapped(data->client, MAX30208_FIFO_DATA);
113		if (ret < 0)
114			goto unlock;
115
116		data_count--;
117	}
118
119unlock:
120	mutex_unlock(&data->lock);
121	return ret;
122}
123
124/**
125 * max30208_config_setup() - Set up FIFO configuration register
126 * @data: Struct comprising member elements of the device
127 *
128 * Sets the rollover bit to '1' to enable overwriting FIFO during overflow.
129 */
130static int max30208_config_setup(struct max30208_data *data)
131{
132	u8 regval;
133	int ret;
134
135	ret = i2c_smbus_read_byte_data(data->client, MAX30208_FIFO_CONFIG);
136	if (ret < 0)
137		return ret;
138
139	regval = ret | MAX30208_FIFO_CONFIG_RO;
140
141	ret = i2c_smbus_write_byte_data(data->client, MAX30208_FIFO_CONFIG, regval);
142	if (ret)
143		return ret;
144
145	return 0;
146}
147
148static int max30208_read(struct iio_dev *indio_dev,
149			 struct iio_chan_spec const *chan,
150			 int *val, int *val2, long mask)
151{
152	struct max30208_data *data = iio_priv(indio_dev);
153	int ret;
154
155	switch (mask) {
156	case IIO_CHAN_INFO_RAW:
157		ret = max30208_update_temp(data);
158		if (ret < 0)
159			return ret;
160
161		*val = sign_extend32(ret, 15);
162		return IIO_VAL_INT;
163
164	case IIO_CHAN_INFO_SCALE:
165		*val = 5;
166		return IIO_VAL_INT;
167
168	default:
169		return -EINVAL;
170	}
171}
172
173static const struct iio_info max30208_info = {
174	.read_raw = max30208_read,
175};
176
177static int max30208_probe(struct i2c_client *i2c)
178{
179	struct device *dev = &i2c->dev;
180	struct max30208_data *data;
181	struct iio_dev *indio_dev;
182	int ret;
183
184	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
185	if (!indio_dev)
186		return -ENOMEM;
187
188	data = iio_priv(indio_dev);
189	data->client = i2c;
190	mutex_init(&data->lock);
191
192	indio_dev->name = "max30208";
193	indio_dev->channels = max30208_channels;
194	indio_dev->num_channels = ARRAY_SIZE(max30208_channels);
195	indio_dev->info = &max30208_info;
196	indio_dev->modes = INDIO_DIRECT_MODE;
197
198	ret = i2c_smbus_write_byte_data(data->client, MAX30208_SYSTEM_CTRL,
199					MAX30208_SYSTEM_CTRL_RESET);
200	if (ret) {
201		dev_err(dev, "Failure in performing reset\n");
202		return ret;
203	}
204
205	msleep(50);
206
207	ret = max30208_config_setup(data);
208	if (ret)
209		return ret;
210
211	ret = devm_iio_device_register(dev, indio_dev);
212	if (ret) {
213		dev_err(dev, "Failed to register IIO device\n");
214		return ret;
215	}
216
217	return 0;
218}
219
220static const struct i2c_device_id max30208_id_table[] = {
221	{ "max30208" },
222	{ }
223};
224MODULE_DEVICE_TABLE(i2c, max30208_id_table);
225
226static const struct acpi_device_id max30208_acpi_match[] = {
227	{ "MAX30208" },
228	{ }
229};
230MODULE_DEVICE_TABLE(acpi, max30208_acpi_match);
231
232static const struct of_device_id max30208_of_match[] = {
233	{ .compatible = "maxim,max30208" },
234	{ }
235};
236MODULE_DEVICE_TABLE(of, max30208_of_match);
237
238static struct i2c_driver max30208_driver = {
239	.driver = {
240		.name = "max30208",
241		.of_match_table = max30208_of_match,
242		.acpi_match_table = max30208_acpi_match,
243	},
244	.probe = max30208_probe,
245	.id_table = max30208_id_table,
246};
247module_i2c_driver(max30208_driver);
248
249MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>");
250MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
251MODULE_LICENSE("GPL");
~/ Read-only file preview.