]> Git Repo - linux.git/blob - drivers/iio/temperature/max30208.c
Linux 6.14-rc3
[linux.git] / drivers / iio / temperature / max30208.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 /*
4  * Copyright (c) Rajat Khandelwal <[email protected]>
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  */
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
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  */
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
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
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 <[email protected]>");
250 MODULE_DESCRIPTION("Maxim MAX30208 digital temperature sensor");
251 MODULE_LICENSE("GPL");
This page took 0.04481 seconds and 4 git commands to generate.