max30102.c (ad90e570e2094537b8eb797fca65c492a7397e32) max30102.c (83e6415d565f6ddfa12a58c3f854c4504bdaa7f9)
1/*
2 * max30102.c - Support for MAX30102 heart rate and pulse oximeter sensor
3 *
4 * Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or

--- 52 unchanged lines hidden (view full) ---

61#define MAX30102_REG_FIFO_DATA_ENTRY_LEN 6
62
63#define MAX30102_REG_FIFO_CONFIG 0x08
64#define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES BIT(1)
65#define MAX30102_REG_FIFO_CONFIG_AVG_SHIFT 5
66#define MAX30102_REG_FIFO_CONFIG_AFULL BIT(0)
67
68#define MAX30102_REG_MODE_CONFIG 0x09
1/*
2 * max30102.c - Support for MAX30102 heart rate and pulse oximeter sensor
3 *
4 * Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or

--- 52 unchanged lines hidden (view full) ---

61#define MAX30102_REG_FIFO_DATA_ENTRY_LEN 6
62
63#define MAX30102_REG_FIFO_CONFIG 0x08
64#define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES BIT(1)
65#define MAX30102_REG_FIFO_CONFIG_AVG_SHIFT 5
66#define MAX30102_REG_FIFO_CONFIG_AFULL BIT(0)
67
68#define MAX30102_REG_MODE_CONFIG 0x09
69#define MAX30102_REG_MODE_CONFIG_MODE_NONE 0x00
69#define MAX30102_REG_MODE_CONFIG_MODE_HR 0x02 /* red LED */
70#define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2 0x03 /* red + IR LED */
71#define MAX30102_REG_MODE_CONFIG_MODE_MULTI 0x07 /* multi-LED mode */
72#define MAX30102_REG_MODE_CONFIG_MODE_MASK GENMASK(2, 0)
73#define MAX30102_REG_MODE_CONFIG_PWR BIT(7)
74
75#define MAX30102_REG_SPO2_CONFIG 0x0a
76#define MAX30102_REG_SPO2_CONFIG_PULSE_411_US 0x03

--- 57 unchanged lines hidden (view full) ---

134 {
135 .type = IIO_TEMP,
136 .info_mask_separate =
137 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
138 .scan_index = -1,
139 },
140};
141
70#define MAX30102_REG_MODE_CONFIG_MODE_HR 0x02 /* red LED */
71#define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2 0x03 /* red + IR LED */
72#define MAX30102_REG_MODE_CONFIG_MODE_MULTI 0x07 /* multi-LED mode */
73#define MAX30102_REG_MODE_CONFIG_MODE_MASK GENMASK(2, 0)
74#define MAX30102_REG_MODE_CONFIG_PWR BIT(7)
75
76#define MAX30102_REG_SPO2_CONFIG 0x0a
77#define MAX30102_REG_SPO2_CONFIG_PULSE_411_US 0x03

--- 57 unchanged lines hidden (view full) ---

135 {
136 .type = IIO_TEMP,
137 .info_mask_separate =
138 BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
139 .scan_index = -1,
140 },
141};
142
142static int max30102_set_powermode(struct max30102_data *data, bool state)
143static int max30102_set_power(struct max30102_data *data, bool en)
143{
144 return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
145 MAX30102_REG_MODE_CONFIG_PWR,
144{
145 return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
146 MAX30102_REG_MODE_CONFIG_PWR,
146 state ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
147 en ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
147}
148
148}
149
150static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
151{
152 u8 reg = mode;
153
154 if (!en)
155 reg |= MAX30102_REG_MODE_CONFIG_PWR;
156
157 return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
158 MAX30102_REG_MODE_CONFIG_PWR |
159 MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
160}
161
149static int max30102_buffer_postenable(struct iio_dev *indio_dev)
150{
151 struct max30102_data *data = iio_priv(indio_dev);
162static int max30102_buffer_postenable(struct iio_dev *indio_dev)
163{
164 struct max30102_data *data = iio_priv(indio_dev);
165 u8 reg;
152
166
153 return max30102_set_powermode(data, true);
167 reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
168
169 return max30102_set_powermode(data, reg, true);
154}
155
156static int max30102_buffer_predisable(struct iio_dev *indio_dev)
157{
158 struct max30102_data *data = iio_priv(indio_dev);
159
170}
171
172static int max30102_buffer_predisable(struct iio_dev *indio_dev)
173{
174 struct max30102_data *data = iio_priv(indio_dev);
175
160 return max30102_set_powermode(data, false);
176 return max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
177 false);
161}
162
163static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = {
164 .postenable = max30102_buffer_postenable,
165 .predisable = max30102_buffer_predisable,
166};
167
168static inline int max30102_fifo_count(struct max30102_data *data)

--- 104 unchanged lines hidden (view full) ---

273{
274 int ret;
275
276 /* setup LED current settings */
277 ret = max30102_led_init(data);
278 if (ret)
279 return ret;
280
178}
179
180static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = {
181 .postenable = max30102_buffer_postenable,
182 .predisable = max30102_buffer_predisable,
183};
184
185static inline int max30102_fifo_count(struct max30102_data *data)

--- 104 unchanged lines hidden (view full) ---

290{
291 int ret;
292
293 /* setup LED current settings */
294 ret = max30102_led_init(data);
295 if (ret)
296 return ret;
297
281 /* enable 18-bit HR + SPO2 readings at 400Hz */
298 /* configure 18-bit HR + SpO2 readings at 400Hz */
282 ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG,
283 (MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS
284 << MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) |
285 (MAX30102_REG_SPO2_CONFIG_SR_400HZ
286 << MAX30102_REG_SPO2_CONFIG_SR_MASK_SHIFT) |
287 MAX30102_REG_SPO2_CONFIG_PULSE_411_US);
288 if (ret)
289 return ret;
290
299 ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG,
300 (MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS
301 << MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) |
302 (MAX30102_REG_SPO2_CONFIG_SR_400HZ
303 << MAX30102_REG_SPO2_CONFIG_SR_MASK_SHIFT) |
304 MAX30102_REG_SPO2_CONFIG_PULSE_411_US);
305 if (ret)
306 return ret;
307
291 /* enable HR + SPO2 mode */
292 ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
293 MAX30102_REG_MODE_CONFIG_MODE_MASK,
294 MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2);
295 if (ret)
296 return ret;
297
298 /* average 4 samples + generate FIFO interrupt */
299 ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG,
300 (MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES
301 << MAX30102_REG_FIFO_CONFIG_AVG_SHIFT) |
302 MAX30102_REG_FIFO_CONFIG_AFULL);
303 if (ret)
304 return ret;
305

--- 23 unchanged lines hidden (view full) ---

329 return 0;
330}
331
332static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
333{
334 int ret;
335
336 if (en) {
308 /* average 4 samples + generate FIFO interrupt */
309 ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG,
310 (MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES
311 << MAX30102_REG_FIFO_CONFIG_AVG_SHIFT) |
312 MAX30102_REG_FIFO_CONFIG_AFULL);
313 if (ret)
314 return ret;
315

--- 23 unchanged lines hidden (view full) ---

339 return 0;
340}
341
342static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
343{
344 int ret;
345
346 if (en) {
337 ret = max30102_set_powermode(data, true);
347 ret = max30102_set_power(data, true);
338 if (ret)
339 return ret;
340 }
341
342 /* start acquisition */
343 ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
344 MAX30102_REG_TEMP_CONFIG_TEMP_EN,
345 MAX30102_REG_TEMP_CONFIG_TEMP_EN);
346 if (ret)
347 goto out;
348
349 msleep(35);
350 ret = max30102_read_temp(data, val);
351
352out:
353 if (en)
348 if (ret)
349 return ret;
350 }
351
352 /* start acquisition */
353 ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
354 MAX30102_REG_TEMP_CONFIG_TEMP_EN,
355 MAX30102_REG_TEMP_CONFIG_TEMP_EN);
356 if (ret)
357 goto out;
358
359 msleep(35);
360 ret = max30102_read_temp(data, val);
361
362out:
363 if (en)
354 max30102_set_powermode(data, false);
364 max30102_set_power(data, false);
355
356 return ret;
357}
358
359static int max30102_read_raw(struct iio_dev *indio_dev,
360 struct iio_chan_spec const *chan,
361 int *val, int *val2, long mask)
362{

--- 80 unchanged lines hidden (view full) ---

443 return -ENODEV;
444
445 /* show revision ID */
446 ret = regmap_read(data->regmap, MAX30102_REG_REV_ID, &reg);
447 if (ret)
448 return ret;
449 dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
450
365
366 return ret;
367}
368
369static int max30102_read_raw(struct iio_dev *indio_dev,
370 struct iio_chan_spec const *chan,
371 int *val, int *val2, long mask)
372{

--- 80 unchanged lines hidden (view full) ---

453 return -ENODEV;
454
455 /* show revision ID */
456 ret = regmap_read(data->regmap, MAX30102_REG_REV_ID, &reg);
457 if (ret)
458 return ret;
459 dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
460
451 ret = max30102_set_powermode(data, false);
461 /* clear mode setting, chip shutdown */
462 ret = max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
463 false);
452 if (ret)
453 return ret;
454
455 ret = max30102_chip_init(data);
456 if (ret)
457 return ret;
458
459 if (client->irq <= 0) {

--- 14 unchanged lines hidden (view full) ---

474}
475
476static int max30102_remove(struct i2c_client *client)
477{
478 struct iio_dev *indio_dev = i2c_get_clientdata(client);
479 struct max30102_data *data = iio_priv(indio_dev);
480
481 iio_device_unregister(indio_dev);
464 if (ret)
465 return ret;
466
467 ret = max30102_chip_init(data);
468 if (ret)
469 return ret;
470
471 if (client->irq <= 0) {

--- 14 unchanged lines hidden (view full) ---

486}
487
488static int max30102_remove(struct i2c_client *client)
489{
490 struct iio_dev *indio_dev = i2c_get_clientdata(client);
491 struct max30102_data *data = iio_priv(indio_dev);
492
493 iio_device_unregister(indio_dev);
482 max30102_set_powermode(data, false);
494 max30102_set_power(data, false);
483
484 return 0;
485}
486
487static const struct i2c_device_id max30102_id[] = {
488 { "max30102", 0 },
489 {}
490};

--- 22 unchanged lines hidden ---
495
496 return 0;
497}
498
499static const struct i2c_device_id max30102_id[] = {
500 { "max30102", 0 },
501 {}
502};

--- 22 unchanged lines hidden ---