1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * max30100.c - Support for MAX30100 heart rate and pulse oximeter sensor |
4 | * |
5 | * Copyright (C) 2015, 2018 |
6 | * Author: Matt Ranostay <matt.ranostay@konsulko.com> |
7 | * |
8 | * TODO: enable pulse length controls via device tree properties |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/init.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/err.h> |
16 | #include <linux/irq.h> |
17 | #include <linux/i2c.h> |
18 | #include <linux/mutex.h> |
19 | #include <linux/property.h> |
20 | #include <linux/regmap.h> |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/buffer.h> |
23 | #include <linux/iio/kfifo_buf.h> |
24 | |
25 | #define MAX30100_REGMAP_NAME "max30100_regmap" |
26 | #define MAX30100_DRV_NAME "max30100" |
27 | |
28 | #define MAX30100_REG_INT_STATUS 0x00 |
29 | #define MAX30100_REG_INT_STATUS_PWR_RDY BIT(0) |
30 | #define MAX30100_REG_INT_STATUS_SPO2_RDY BIT(4) |
31 | #define MAX30100_REG_INT_STATUS_HR_RDY BIT(5) |
32 | #define MAX30100_REG_INT_STATUS_FIFO_RDY BIT(7) |
33 | |
34 | #define MAX30100_REG_INT_ENABLE 0x01 |
35 | #define MAX30100_REG_INT_ENABLE_SPO2_EN BIT(0) |
36 | #define MAX30100_REG_INT_ENABLE_HR_EN BIT(1) |
37 | #define MAX30100_REG_INT_ENABLE_FIFO_EN BIT(3) |
38 | #define MAX30100_REG_INT_ENABLE_MASK 0xf0 |
39 | #define MAX30100_REG_INT_ENABLE_MASK_SHIFT 4 |
40 | |
41 | #define MAX30100_REG_FIFO_WR_PTR 0x02 |
42 | #define MAX30100_REG_FIFO_OVR_CTR 0x03 |
43 | #define MAX30100_REG_FIFO_RD_PTR 0x04 |
44 | #define MAX30100_REG_FIFO_DATA 0x05 |
45 | #define MAX30100_REG_FIFO_DATA_ENTRY_COUNT 16 |
46 | #define MAX30100_REG_FIFO_DATA_ENTRY_LEN 4 |
47 | |
48 | #define MAX30100_REG_MODE_CONFIG 0x06 |
49 | #define MAX30100_REG_MODE_CONFIG_MODE_SPO2_EN BIT(0) |
50 | #define MAX30100_REG_MODE_CONFIG_MODE_HR_EN BIT(1) |
51 | #define MAX30100_REG_MODE_CONFIG_MODE_MASK 0x03 |
52 | #define MAX30100_REG_MODE_CONFIG_TEMP_EN BIT(3) |
53 | #define MAX30100_REG_MODE_CONFIG_PWR BIT(7) |
54 | |
55 | #define MAX30100_REG_SPO2_CONFIG 0x07 |
56 | #define MAX30100_REG_SPO2_CONFIG_100HZ BIT(2) |
57 | #define MAX30100_REG_SPO2_CONFIG_HI_RES_EN BIT(6) |
58 | #define MAX30100_REG_SPO2_CONFIG_1600US 0x3 |
59 | |
60 | #define MAX30100_REG_LED_CONFIG 0x09 |
61 | #define MAX30100_REG_LED_CONFIG_LED_MASK 0x0f |
62 | #define MAX30100_REG_LED_CONFIG_RED_LED_SHIFT 4 |
63 | |
64 | #define MAX30100_REG_LED_CONFIG_24MA 0x07 |
65 | #define MAX30100_REG_LED_CONFIG_50MA 0x0f |
66 | |
67 | #define MAX30100_REG_TEMP_INTEGER 0x16 |
68 | #define MAX30100_REG_TEMP_FRACTION 0x17 |
69 | |
70 | struct max30100_data { |
71 | struct i2c_client *client; |
72 | struct iio_dev *indio_dev; |
73 | struct mutex lock; |
74 | struct regmap *regmap; |
75 | |
76 | __be16 buffer[2]; /* 2 16-bit channels */ |
77 | }; |
78 | |
79 | static bool max30100_is_volatile_reg(struct device *dev, unsigned int reg) |
80 | { |
81 | switch (reg) { |
82 | case MAX30100_REG_INT_STATUS: |
83 | case MAX30100_REG_MODE_CONFIG: |
84 | case MAX30100_REG_FIFO_WR_PTR: |
85 | case MAX30100_REG_FIFO_OVR_CTR: |
86 | case MAX30100_REG_FIFO_RD_PTR: |
87 | case MAX30100_REG_FIFO_DATA: |
88 | case MAX30100_REG_TEMP_INTEGER: |
89 | case MAX30100_REG_TEMP_FRACTION: |
90 | return true; |
91 | default: |
92 | return false; |
93 | } |
94 | } |
95 | |
96 | static const struct regmap_config max30100_regmap_config = { |
97 | .name = MAX30100_REGMAP_NAME, |
98 | |
99 | .reg_bits = 8, |
100 | .val_bits = 8, |
101 | |
102 | .max_register = MAX30100_REG_TEMP_FRACTION, |
103 | .cache_type = REGCACHE_FLAT, |
104 | |
105 | .volatile_reg = max30100_is_volatile_reg, |
106 | }; |
107 | |
108 | static const unsigned int max30100_led_current_mapping[] = { |
109 | 4400, 7600, 11000, 14200, 17400, |
110 | 20800, 24000, 27100, 30600, 33800, |
111 | 37000, 40200, 43600, 46800, 50000 |
112 | }; |
113 | |
114 | static const unsigned long max30100_scan_masks[] = {0x3, 0}; |
115 | |
116 | static const struct iio_chan_spec max30100_channels[] = { |
117 | { |
118 | .type = IIO_INTENSITY, |
119 | .channel2 = IIO_MOD_LIGHT_IR, |
120 | .modified = 1, |
121 | |
122 | .scan_index = 0, |
123 | .scan_type = { |
124 | .sign = 'u', |
125 | .realbits = 16, |
126 | .storagebits = 16, |
127 | .endianness = IIO_BE, |
128 | }, |
129 | }, |
130 | { |
131 | .type = IIO_INTENSITY, |
132 | .channel2 = IIO_MOD_LIGHT_RED, |
133 | .modified = 1, |
134 | |
135 | .scan_index = 1, |
136 | .scan_type = { |
137 | .sign = 'u', |
138 | .realbits = 16, |
139 | .storagebits = 16, |
140 | .endianness = IIO_BE, |
141 | }, |
142 | }, |
143 | { |
144 | .type = IIO_TEMP, |
145 | .info_mask_separate = |
146 | BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), |
147 | .scan_index = -1, |
148 | }, |
149 | }; |
150 | |
151 | static int max30100_set_powermode(struct max30100_data *data, bool state) |
152 | { |
153 | return regmap_update_bits(map: data->regmap, MAX30100_REG_MODE_CONFIG, |
154 | MAX30100_REG_MODE_CONFIG_PWR, |
155 | val: state ? 0 : MAX30100_REG_MODE_CONFIG_PWR); |
156 | } |
157 | |
158 | static int max30100_clear_fifo(struct max30100_data *data) |
159 | { |
160 | int ret; |
161 | |
162 | ret = regmap_write(map: data->regmap, MAX30100_REG_FIFO_WR_PTR, val: 0); |
163 | if (ret) |
164 | return ret; |
165 | |
166 | ret = regmap_write(map: data->regmap, MAX30100_REG_FIFO_OVR_CTR, val: 0); |
167 | if (ret) |
168 | return ret; |
169 | |
170 | return regmap_write(map: data->regmap, MAX30100_REG_FIFO_RD_PTR, val: 0); |
171 | } |
172 | |
173 | static int max30100_buffer_postenable(struct iio_dev *indio_dev) |
174 | { |
175 | struct max30100_data *data = iio_priv(indio_dev); |
176 | int ret; |
177 | |
178 | ret = max30100_set_powermode(data, state: true); |
179 | if (ret) |
180 | return ret; |
181 | |
182 | return max30100_clear_fifo(data); |
183 | } |
184 | |
185 | static int max30100_buffer_predisable(struct iio_dev *indio_dev) |
186 | { |
187 | struct max30100_data *data = iio_priv(indio_dev); |
188 | |
189 | return max30100_set_powermode(data, state: false); |
190 | } |
191 | |
192 | static const struct iio_buffer_setup_ops max30100_buffer_setup_ops = { |
193 | .postenable = max30100_buffer_postenable, |
194 | .predisable = max30100_buffer_predisable, |
195 | }; |
196 | |
197 | static inline int max30100_fifo_count(struct max30100_data *data) |
198 | { |
199 | unsigned int val; |
200 | int ret; |
201 | |
202 | ret = regmap_read(map: data->regmap, MAX30100_REG_INT_STATUS, val: &val); |
203 | if (ret) |
204 | return ret; |
205 | |
206 | /* FIFO is almost full */ |
207 | if (val & MAX30100_REG_INT_STATUS_FIFO_RDY) |
208 | return MAX30100_REG_FIFO_DATA_ENTRY_COUNT - 1; |
209 | |
210 | return 0; |
211 | } |
212 | |
213 | static int max30100_read_measurement(struct max30100_data *data) |
214 | { |
215 | int ret; |
216 | |
217 | ret = i2c_smbus_read_i2c_block_data(client: data->client, |
218 | MAX30100_REG_FIFO_DATA, |
219 | MAX30100_REG_FIFO_DATA_ENTRY_LEN, |
220 | values: (u8 *) &data->buffer); |
221 | |
222 | return (ret == MAX30100_REG_FIFO_DATA_ENTRY_LEN) ? 0 : ret; |
223 | } |
224 | |
225 | static irqreturn_t max30100_interrupt_handler(int irq, void *private) |
226 | { |
227 | struct iio_dev *indio_dev = private; |
228 | struct max30100_data *data = iio_priv(indio_dev); |
229 | int ret, cnt = 0; |
230 | |
231 | mutex_lock(&data->lock); |
232 | |
233 | while (cnt || (cnt = max30100_fifo_count(data)) > 0) { |
234 | ret = max30100_read_measurement(data); |
235 | if (ret) |
236 | break; |
237 | |
238 | iio_push_to_buffers(indio_dev: data->indio_dev, data: data->buffer); |
239 | cnt--; |
240 | } |
241 | |
242 | mutex_unlock(lock: &data->lock); |
243 | |
244 | return IRQ_HANDLED; |
245 | } |
246 | |
247 | static int max30100_get_current_idx(unsigned int val, int *reg) |
248 | { |
249 | int idx; |
250 | |
251 | /* LED turned off */ |
252 | if (val == 0) { |
253 | *reg = 0; |
254 | return 0; |
255 | } |
256 | |
257 | for (idx = 0; idx < ARRAY_SIZE(max30100_led_current_mapping); idx++) { |
258 | if (max30100_led_current_mapping[idx] == val) { |
259 | *reg = idx + 1; |
260 | return 0; |
261 | } |
262 | } |
263 | |
264 | return -EINVAL; |
265 | } |
266 | |
267 | static int max30100_led_init(struct max30100_data *data) |
268 | { |
269 | struct device *dev = &data->client->dev; |
270 | unsigned int val[2]; |
271 | int reg, ret; |
272 | |
273 | ret = device_property_read_u32_array(dev, propname: "maxim,led-current-microamp" , |
274 | val: (unsigned int *) &val, nval: 2); |
275 | if (ret) { |
276 | /* Default to 24 mA RED LED, 50 mA IR LED */ |
277 | reg = (MAX30100_REG_LED_CONFIG_24MA << |
278 | MAX30100_REG_LED_CONFIG_RED_LED_SHIFT) | |
279 | MAX30100_REG_LED_CONFIG_50MA; |
280 | dev_warn(dev, "no led-current-microamp set" ); |
281 | |
282 | return regmap_write(map: data->regmap, MAX30100_REG_LED_CONFIG, val: reg); |
283 | } |
284 | |
285 | /* RED LED current */ |
286 | ret = max30100_get_current_idx(val: val[0], reg: ®); |
287 | if (ret) { |
288 | dev_err(dev, "invalid RED current setting %d" , val[0]); |
289 | return ret; |
290 | } |
291 | |
292 | ret = regmap_update_bits(map: data->regmap, MAX30100_REG_LED_CONFIG, |
293 | MAX30100_REG_LED_CONFIG_LED_MASK << |
294 | MAX30100_REG_LED_CONFIG_RED_LED_SHIFT, |
295 | val: reg << MAX30100_REG_LED_CONFIG_RED_LED_SHIFT); |
296 | if (ret) |
297 | return ret; |
298 | |
299 | /* IR LED current */ |
300 | ret = max30100_get_current_idx(val: val[1], reg: ®); |
301 | if (ret) { |
302 | dev_err(dev, "invalid IR current setting %d" , val[1]); |
303 | return ret; |
304 | } |
305 | |
306 | return regmap_update_bits(map: data->regmap, MAX30100_REG_LED_CONFIG, |
307 | MAX30100_REG_LED_CONFIG_LED_MASK, val: reg); |
308 | } |
309 | |
310 | static int max30100_chip_init(struct max30100_data *data) |
311 | { |
312 | int ret; |
313 | |
314 | /* setup LED current settings */ |
315 | ret = max30100_led_init(data); |
316 | if (ret) |
317 | return ret; |
318 | |
319 | /* enable hi-res SPO2 readings at 100Hz */ |
320 | ret = regmap_write(map: data->regmap, MAX30100_REG_SPO2_CONFIG, |
321 | MAX30100_REG_SPO2_CONFIG_HI_RES_EN | |
322 | MAX30100_REG_SPO2_CONFIG_100HZ); |
323 | if (ret) |
324 | return ret; |
325 | |
326 | /* enable SPO2 mode */ |
327 | ret = regmap_update_bits(map: data->regmap, MAX30100_REG_MODE_CONFIG, |
328 | MAX30100_REG_MODE_CONFIG_MODE_MASK, |
329 | MAX30100_REG_MODE_CONFIG_MODE_HR_EN | |
330 | MAX30100_REG_MODE_CONFIG_MODE_SPO2_EN); |
331 | if (ret) |
332 | return ret; |
333 | |
334 | /* enable FIFO interrupt */ |
335 | return regmap_update_bits(map: data->regmap, MAX30100_REG_INT_ENABLE, |
336 | MAX30100_REG_INT_ENABLE_MASK, |
337 | MAX30100_REG_INT_ENABLE_FIFO_EN |
338 | << MAX30100_REG_INT_ENABLE_MASK_SHIFT); |
339 | } |
340 | |
341 | static int max30100_read_temp(struct max30100_data *data, int *val) |
342 | { |
343 | int ret; |
344 | unsigned int reg; |
345 | |
346 | ret = regmap_read(map: data->regmap, MAX30100_REG_TEMP_INTEGER, val: ®); |
347 | if (ret < 0) |
348 | return ret; |
349 | *val = reg << 4; |
350 | |
351 | ret = regmap_read(map: data->regmap, MAX30100_REG_TEMP_FRACTION, val: ®); |
352 | if (ret < 0) |
353 | return ret; |
354 | |
355 | *val |= reg & 0xf; |
356 | *val = sign_extend32(value: *val, index: 11); |
357 | |
358 | return 0; |
359 | } |
360 | |
361 | static int max30100_get_temp(struct max30100_data *data, int *val) |
362 | { |
363 | int ret; |
364 | |
365 | /* start acquisition */ |
366 | ret = regmap_update_bits(map: data->regmap, MAX30100_REG_MODE_CONFIG, |
367 | MAX30100_REG_MODE_CONFIG_TEMP_EN, |
368 | MAX30100_REG_MODE_CONFIG_TEMP_EN); |
369 | if (ret) |
370 | return ret; |
371 | |
372 | msleep(msecs: 35); |
373 | |
374 | return max30100_read_temp(data, val); |
375 | } |
376 | |
377 | static int max30100_read_raw(struct iio_dev *indio_dev, |
378 | struct iio_chan_spec const *chan, |
379 | int *val, int *val2, long mask) |
380 | { |
381 | struct max30100_data *data = iio_priv(indio_dev); |
382 | int ret = -EINVAL; |
383 | |
384 | switch (mask) { |
385 | case IIO_CHAN_INFO_RAW: |
386 | /* |
387 | * Temperature reading can only be acquired while engine |
388 | * is running |
389 | */ |
390 | if (iio_device_claim_buffer_mode(indio_dev)) { |
391 | /* |
392 | * Replacing -EBUSY or other error code |
393 | * returned by iio_device_claim_buffer_mode() |
394 | * because user space may rely on the current |
395 | * one. |
396 | */ |
397 | ret = -EAGAIN; |
398 | } else { |
399 | ret = max30100_get_temp(data, val); |
400 | if (!ret) |
401 | ret = IIO_VAL_INT; |
402 | |
403 | iio_device_release_buffer_mode(indio_dev); |
404 | } |
405 | break; |
406 | case IIO_CHAN_INFO_SCALE: |
407 | *val = 1; /* 0.0625 */ |
408 | *val2 = 16; |
409 | ret = IIO_VAL_FRACTIONAL; |
410 | break; |
411 | } |
412 | |
413 | return ret; |
414 | } |
415 | |
416 | static const struct iio_info max30100_info = { |
417 | .read_raw = max30100_read_raw, |
418 | }; |
419 | |
420 | static int max30100_probe(struct i2c_client *client) |
421 | { |
422 | struct max30100_data *data; |
423 | struct iio_dev *indio_dev; |
424 | int ret; |
425 | |
426 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data)); |
427 | if (!indio_dev) |
428 | return -ENOMEM; |
429 | |
430 | indio_dev->name = MAX30100_DRV_NAME; |
431 | indio_dev->channels = max30100_channels; |
432 | indio_dev->info = &max30100_info; |
433 | indio_dev->num_channels = ARRAY_SIZE(max30100_channels); |
434 | indio_dev->available_scan_masks = max30100_scan_masks; |
435 | indio_dev->modes = INDIO_DIRECT_MODE; |
436 | |
437 | ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev, |
438 | &max30100_buffer_setup_ops); |
439 | if (ret) |
440 | return ret; |
441 | |
442 | data = iio_priv(indio_dev); |
443 | data->indio_dev = indio_dev; |
444 | data->client = client; |
445 | |
446 | mutex_init(&data->lock); |
447 | i2c_set_clientdata(client, data: indio_dev); |
448 | |
449 | data->regmap = devm_regmap_init_i2c(client, &max30100_regmap_config); |
450 | if (IS_ERR(ptr: data->regmap)) { |
451 | dev_err(&client->dev, "regmap initialization failed.\n" ); |
452 | return PTR_ERR(ptr: data->regmap); |
453 | } |
454 | max30100_set_powermode(data, state: false); |
455 | |
456 | ret = max30100_chip_init(data); |
457 | if (ret) |
458 | return ret; |
459 | |
460 | if (client->irq <= 0) { |
461 | dev_err(&client->dev, "no valid irq defined\n" ); |
462 | return -EINVAL; |
463 | } |
464 | ret = devm_request_threaded_irq(dev: &client->dev, irq: client->irq, |
465 | NULL, thread_fn: max30100_interrupt_handler, |
466 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
467 | devname: "max30100_irq" , dev_id: indio_dev); |
468 | if (ret) { |
469 | dev_err(&client->dev, "request irq (%d) failed\n" , client->irq); |
470 | return ret; |
471 | } |
472 | |
473 | return iio_device_register(indio_dev); |
474 | } |
475 | |
476 | static void max30100_remove(struct i2c_client *client) |
477 | { |
478 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
479 | struct max30100_data *data = iio_priv(indio_dev); |
480 | |
481 | iio_device_unregister(indio_dev); |
482 | max30100_set_powermode(data, state: false); |
483 | } |
484 | |
485 | static const struct i2c_device_id max30100_id[] = { |
486 | { "max30100" , 0 }, |
487 | {} |
488 | }; |
489 | MODULE_DEVICE_TABLE(i2c, max30100_id); |
490 | |
491 | static const struct of_device_id max30100_dt_ids[] = { |
492 | { .compatible = "maxim,max30100" }, |
493 | { } |
494 | }; |
495 | MODULE_DEVICE_TABLE(of, max30100_dt_ids); |
496 | |
497 | static struct i2c_driver max30100_driver = { |
498 | .driver = { |
499 | .name = MAX30100_DRV_NAME, |
500 | .of_match_table = max30100_dt_ids, |
501 | }, |
502 | .probe = max30100_probe, |
503 | .remove = max30100_remove, |
504 | .id_table = max30100_id, |
505 | }; |
506 | module_i2c_driver(max30100_driver); |
507 | |
508 | MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>" ); |
509 | MODULE_DESCRIPTION("MAX30100 heart rate and pulse oximeter sensor" ); |
510 | MODULE_LICENSE("GPL" ); |
511 | |