xref: /linux/drivers/iio/temperature/max30208.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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 
35 struct max30208_data {
36 	struct i2c_client *client;
37 	struct mutex lock; /* Lock to prevent concurrent reads of temperature readings */
38 };
39 
40 static 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  */
max30208_request(struct max30208_data * data)53 static 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 
max30208_update_temp(struct max30208_data * data)88 static 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 
119 unlock:
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  */
max30208_config_setup(struct max30208_data * data)130 static 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 
max30208_read(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)148 static 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 
173 static const struct iio_info max30208_info = {
174 	.read_raw = max30208_read,
175 };
176 
max30208_probe(struct i2c_client * i2c)177 static 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 
220 static const struct i2c_device_id max30208_id_table[] = {
221 	{ "max30208" },
222 	{ }
223 };
224 MODULE_DEVICE_TABLE(i2c, max30208_id_table);
225 
226 static const struct acpi_device_id max30208_acpi_match[] = {
227 	{ "MAX30208" },
228 	{ }
229 };
230 MODULE_DEVICE_TABLE(acpi, max30208_acpi_match);
231 
232 static const struct of_device_id max30208_of_match[] = {
233 	{ .compatible = "maxim,max30208" },
234 	{ }
235 };
236 MODULE_DEVICE_TABLE(of, max30208_of_match);
237 
238 static 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 };
247 module_i2c_driver(max30208_driver);
248 
249 MODULE_AUTHOR("Rajat Khandelwal <rajat.khandelwal@linux.intel.com>");
250 MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
251 MODULE_LICENSE("GPL");
252