Skip to content

Commit 98fc2fb

Browse files
committed
drivers: sensor: max30101: Enable support for multiple instance
The max30101 sensor driver doesn't support multiple instance. Update Kconfig and maxim,max30101.yaml for instance based configuration. Propagate changes over existing files. Signed-off-by: Logan Saint-Germain <[email protected]>
1 parent 36bc2f3 commit 98fc2fb

File tree

7 files changed

+227
-283
lines changed

7 files changed

+227
-283
lines changed

boards/nxp/hexiwear/hexiwear_mk64f12.dts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
/* SPDX-License-Identifier: Apache-2.0 */
1+
/*
2+
* Copyright (c) 2022, NXP
3+
* Copyright (c) 2025, CATIE
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
27

38
/dts-v1/;
49

@@ -124,6 +129,7 @@
124129
status = "disabled";
125130
compatible = "maxim,max30101";
126131
reg = <0x57>;
132+
acq-mode = "multi-led";
127133
};
128134
};
129135

Lines changed: 5 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -1,205 +1,12 @@
11
# MAX30101 heart rate sensor
2-
2+
#
33
# Copyright (c) 2017, NXP
4+
# Copyright (c) 2025, CATIE
5+
#
46
# SPDX-License-Identifier: Apache-2.0
57

6-
menuconfig MAX30101
8+
config MAX30101
79
bool "MAX30101 Pulse Oximeter and Heart Rate Sensor"
810
default y
911
depends on DT_HAS_MAXIM_MAX30101_ENABLED
10-
select I2C
11-
12-
if MAX30101
13-
14-
config MAX30101_SMP_AVE
15-
int "Sample averaging"
16-
range 0 7
17-
default 0
18-
help
19-
To reduce the amount of data throughput, adjacent samples (in each
20-
individual channel) can be averaged and decimated on the chip by
21-
setting this register. Set to 0 for no averaging.
22-
0 = 1 sample (no averaging)
23-
1 = 2 samples
24-
2 = 4 samples
25-
3 = 8 samples
26-
4 = 16 samples
27-
5 = 32 samples
28-
6 = 32 samples
29-
7 = 32 samples
30-
31-
config MAX30101_FIFO_ROLLOVER_EN
32-
bool "FIFO rolls on full"
33-
help
34-
Controls the behavior of the FIFO when the FIFO becomes completely
35-
filled with data. If set, the FIFO address rolls over to zero and the
36-
FIFO continues to fill with new data. If not set, then the FIFO is
37-
not updated until FIFO_DATA is read or the WRITE/READ pointer
38-
positions are changed.
39-
40-
config MAX30101_FIFO_A_FULL
41-
int "FIFO almost full value"
42-
range 0 15
43-
default 0
44-
help
45-
Set the trigger for the FIFO_A_FULL interrupt
46-
47-
choice MAX30101_MODE
48-
prompt "Mode control"
49-
default MAX30101_MULTI_LED_MODE
50-
51-
config MAX30101_HEART_RATE_MODE
52-
bool "Heart rate mode"
53-
help
54-
Set to operate in heart rate only mode. The red LED channel is
55-
active.
56-
57-
config MAX30101_SPO2_MODE
58-
bool "SpO2 mode"
59-
help
60-
Set to operate in SpO2 mode. The red and IR LED channels are active.
61-
62-
config MAX30101_MULTI_LED_MODE
63-
bool "Multi-LED mode"
64-
help
65-
Set to operate in multi-LED mode. The green, red, and/or IR LED
66-
channels are active.
67-
68-
endchoice
69-
70-
config MAX30101_ADC_RGE
71-
int "ADC range control"
72-
range 0 3
73-
default 2
74-
help
75-
Set the ADC's full-scale range.
76-
0 = 7.81 pA/LSB
77-
1 = 15.63 pA/LSB
78-
2 = 31.25 pA/LSB
79-
3 = 62.5 pA/LSB
80-
81-
config MAX30101_SR
82-
int "ADC sample rate control"
83-
range 0 7
84-
default 0
85-
help
86-
Set the effective sampling rate with one sample consisting of one
87-
pulse/conversion per active LED channel. In SpO2 mode, these means
88-
one IR pulse/conversion and one red pulse/conversion per sample
89-
period.
90-
0 = 50 Hz
91-
1 = 100 Hz
92-
2 = 200 Hz
93-
3 = 400 Hz
94-
4 = 800 Hz
95-
5 = 1000 Hz
96-
6 = 1600 Hz
97-
7 = 3200 Hz
98-
99-
config MAX30101_LED1_PA
100-
hex "LED1 (red) pulse amplitude"
101-
range 0 0xff
102-
default 0xff
103-
help
104-
Set the pulse amplitude to control the LED1 (red) current. The actual
105-
measured LED current for each part can vary significantly due to the
106-
trimming methodology.
107-
0x00 = 0.0 mA
108-
0x01 = 0.2 mA
109-
0x02 = 0.4 mA
110-
0x0f = 3.1 mA
111-
0xff = 50.0 mA
112-
113-
config MAX30101_LED2_PA
114-
hex "LED2 (IR) pulse amplitude"
115-
range 0 0xff
116-
default 0x33
117-
help
118-
Set the pulse amplitude to control the LED2 (IR) current. The actual
119-
measured LED current for each part can vary significantly due to the
120-
trimming methodology.
121-
0x00 = 0.0 mA
122-
0x01 = 0.2 mA
123-
0x02 = 0.4 mA
124-
0x0f = 3.1 mA
125-
0xff = 50.0 mA
126-
127-
config MAX30101_LED3_PA
128-
hex "LED3 (green) pulse amplitude"
129-
range 0 0xff
130-
default 0xff
131-
help
132-
Set the pulse amplitude to control the LED3 (green) current. The
133-
actual measured LED current for each part can vary significantly due
134-
to the trimming methodology.
135-
0x00 = 0.0 mA
136-
0x01 = 0.2 mA
137-
0x02 = 0.4 mA
138-
0x0f = 3.1 mA
139-
0xff = 50.0 mA
140-
141-
if MAX30101_MULTI_LED_MODE
142-
143-
config MAX30101_SLOT1
144-
int "Slot 1"
145-
range 0 7
146-
default 3
147-
help
148-
Set which LED and pulse amplitude are active in time slot 1.
149-
0: None (disabled)
150-
1: LED1 (red), LED1_PA
151-
2: LED2 (IR), LED2_PA
152-
3: LED3 (green), LED3_PA
153-
4: None (disabled)
154-
5: LED1 (red), PILOT_PA
155-
6: LED2 (IR), PILOT_PA
156-
7: LED3 (green), PILOT_PA
157-
158-
config MAX30101_SLOT2
159-
int "Slot 2"
160-
range 0 7
161-
default 0
162-
help
163-
Set which LED and pulse amplitude are active in time slot 2.
164-
0: None (disabled)
165-
1: LED1 (red), LED1_PA
166-
2: LED2 (IR), LED2_PA
167-
3: LED3 (green), LED3_PA
168-
4: None (disabled)
169-
5: LED1 (red), PILOT_PA
170-
6: LED2 (IR), PILOT_PA
171-
7: LED3 (green), PILOT_PA
172-
173-
config MAX30101_SLOT3
174-
int "Slot 3"
175-
range 0 7
176-
default 0
177-
help
178-
Set which LED and pulse amplitude are active in time slot 3.
179-
0: None (disabled)
180-
1: LED1 (red), LED1_PA
181-
2: LED2 (IR), LED2_PA
182-
3: LED3 (green), LED3_PA
183-
4: None (disabled)
184-
5: LED1 (red), PILOT_PA
185-
6: LED2 (IR), PILOT_PA
186-
7: LED3 (green), PILOT_PA
187-
188-
config MAX30101_SLOT4
189-
int "Slot 4"
190-
range 0 7
191-
default 0
192-
help
193-
Set which LED and pulse amplitude are active in time slot 4.
194-
0: None (disabled)
195-
1: LED1 (red), LED1_PA
196-
2: LED2 (IR), LED2_PA
197-
3: LED3 (green), LED3_PA
198-
4: None (disabled)
199-
5: LED1 (red), PILOT_PA
200-
6: LED2 (IR), PILOT_PA
201-
7: LED3 (green), PILOT_PA
202-
203-
endif # MAX30101_MULTI_LED_MODE
204-
205-
endif # MAX30101
12+
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_MAXIM_MAX30101),i2c)

drivers/sensor/maxim/max30101/max30101.c

Lines changed: 53 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ static int max30101_init(const struct device *dev)
100100
uint8_t part_id;
101101
uint8_t mode_cfg;
102102
uint32_t led_chan;
103-
int fifo_chan;
104103

105104
if (!device_is_ready(config->i2c.bus)) {
106105
LOG_ERR("Bus device is not ready");
@@ -142,7 +141,7 @@ static int max30101_init(const struct device *dev)
142141

143142
/* Write the mode configuration register */
144143
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MODE_CFG,
145-
config->mode)) {
144+
max30101_mode_convert[config->mode])) {
146145
return -EIO;
147146
}
148147

@@ -165,23 +164,24 @@ static int max30101_init(const struct device *dev)
165164
config->led_pa[2])) {
166165
return -EIO;
167166
}
167+
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_LED4_PA, config->led_pa[2])) {
168+
return -EIO;
169+
}
168170

169-
#ifdef CONFIG_MAX30101_MULTI_LED_MODE
170-
uint8_t multi_led[2];
171+
if (!config->mode) {
172+
uint8_t multi_led[2];
171173

172-
/* Write the multi-LED mode control registers */
173-
multi_led[0] = (config->slot[1] << 4) | (config->slot[0]);
174-
multi_led[1] = (config->slot[3] << 4) | (config->slot[2]);
174+
/* Write the multi-LED mode control registers */
175+
multi_led[0] = (config->slot[1] << 4) | (config->slot[0]);
176+
multi_led[1] = (config->slot[3] << 4) | (config->slot[2]);
175177

176-
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MULTI_LED,
177-
multi_led[0])) {
178-
return -EIO;
179-
}
180-
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MULTI_LED + 1,
181-
multi_led[1])) {
182-
return -EIO;
178+
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MULTI_LED, multi_led[0])) {
179+
return -EIO;
180+
}
181+
if (i2c_reg_write_byte_dt(&config->i2c, MAX30101_REG_MULTI_LED + 1, multi_led[1])) {
182+
return -EIO;
183+
}
183184
}
184-
#endif
185185

186186
/* Initialize the channel map and active channel count */
187187
data->num_channels = 0U;
@@ -192,9 +192,8 @@ static int max30101_init(const struct device *dev)
192192
/* Count the number of active channels and build a map that translates
193193
* the LED channel number (red/ir/green) to the fifo channel number.
194194
*/
195-
for (fifo_chan = 0; fifo_chan < MAX30101_MAX_NUM_CHANNELS;
196-
fifo_chan++) {
197-
led_chan = (config->slot[fifo_chan] & MAX30101_SLOT_LED_MASK)-1;
195+
for (int fifo_chan = 0; fifo_chan < MAX30101_MAX_NUM_CHANNELS; fifo_chan++) {
196+
led_chan = (config->slot[fifo_chan] & MAX30101_SLOT_LED_MASK) - 1;
198197
if (led_chan < MAX30101_MAX_NUM_CHANNELS) {
199198
data->map[led_chan] = fifo_chan;
200199
data->num_channels++;
@@ -204,47 +203,39 @@ static int max30101_init(const struct device *dev)
204203
return 0;
205204
}
206205

207-
static struct max30101_config max30101_config = {
208-
.i2c = I2C_DT_SPEC_INST_GET(0),
209-
.fifo = (CONFIG_MAX30101_SMP_AVE << MAX30101_FIFO_CFG_SMP_AVE_SHIFT) |
210-
#ifdef CONFIG_MAX30101_FIFO_ROLLOVER_EN
211-
MAX30101_FIFO_CFG_ROLLOVER_EN_MASK |
212-
#endif
213-
(CONFIG_MAX30101_FIFO_A_FULL <<
214-
MAX30101_FIFO_CFG_FIFO_FULL_SHIFT),
215-
216-
#if defined(CONFIG_MAX30101_HEART_RATE_MODE)
217-
.mode = MAX30101_MODE_HEART_RATE,
218-
.slot[0] = MAX30101_SLOT_RED_LED1_PA,
219-
.slot[1] = MAX30101_SLOT_DISABLED,
220-
.slot[2] = MAX30101_SLOT_DISABLED,
221-
.slot[3] = MAX30101_SLOT_DISABLED,
222-
#elif defined(CONFIG_MAX30101_SPO2_MODE)
223-
.mode = MAX30101_MODE_SPO2,
224-
.slot[0] = MAX30101_SLOT_RED_LED1_PA,
225-
.slot[1] = MAX30101_SLOT_IR_LED2_PA,
226-
.slot[2] = MAX30101_SLOT_DISABLED,
227-
.slot[3] = MAX30101_SLOT_DISABLED,
228-
#else
229-
.mode = MAX30101_MODE_MULTI_LED,
230-
.slot[0] = CONFIG_MAX30101_SLOT1,
231-
.slot[1] = CONFIG_MAX30101_SLOT2,
232-
.slot[2] = CONFIG_MAX30101_SLOT3,
233-
.slot[3] = CONFIG_MAX30101_SLOT4,
234-
#endif
235-
236-
.spo2 = (CONFIG_MAX30101_ADC_RGE << MAX30101_SPO2_ADC_RGE_SHIFT) |
237-
(CONFIG_MAX30101_SR << MAX30101_SPO2_SR_SHIFT) |
238-
(MAX30101_PW_18BITS << MAX30101_SPO2_PW_SHIFT),
239-
240-
.led_pa[0] = CONFIG_MAX30101_LED1_PA,
241-
.led_pa[1] = CONFIG_MAX30101_LED2_PA,
242-
.led_pa[2] = CONFIG_MAX30101_LED3_PA,
243-
};
244-
245-
static struct max30101_data max30101_data;
246-
247-
SENSOR_DEVICE_DT_INST_DEFINE(0, max30101_init, NULL,
248-
&max30101_data, &max30101_config,
249-
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
250-
&max30101_driver_api);
206+
#define MAX30101_CHECK(n) \
207+
BUILD_ASSERT(DT_INST_PROP_LEN(n, led_pa) == 3, \
208+
"MAX30101 led-pa property must have exactly 3 elements"); \
209+
BUILD_ASSERT(DT_INST_PROP_LEN(n, led_slot) == 4, \
210+
"MAX30101 led-slot property must have exactly 4 elements")
211+
212+
#define MAX30101_SLOT_CFG(n) \
213+
COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, acq_mode, heart_rate), \
214+
(MAX30101_HR_SLOTS), \
215+
(COND_CODE_1(DT_INST_ENUM_HAS_VALUE(n, acq_mode, spo2), \
216+
(MAX30101_SPO2_SLOTS), \
217+
(MAX30101_MULTI_LED(n)) \
218+
)) \
219+
)
220+
221+
#define MAX30101_INIT(n) \
222+
MAX30101_CHECK(n); \
223+
static const struct max30101_config max30101_config_##n = { \
224+
.i2c = I2C_DT_SPEC_INST_GET(n), \
225+
.fifo = (DT_INST_ENUM_IDX(n, smp_ave) << MAX30101_FIFO_CFG_SMP_AVE_SHIFT) | \
226+
(DT_INST_PROP(n, fifo_rollover_en) \
227+
<< MAX30101_FIFO_CFG_ROLLOVER_EN_SHIFT) | \
228+
(DT_INST_PROP(n, fifo_a_full) << MAX30101_FIFO_CFG_FIFO_FULL_SHIFT), \
229+
.mode = DT_INST_ENUM_IDX(n, acq_mode), \
230+
.spo2 = (DT_INST_ENUM_IDX(n, adc_rge) << MAX30101_SPO2_ADC_RGE_SHIFT) | \
231+
(DT_INST_ENUM_IDX(n, smp_sr) << MAX30101_SPO2_SR_SHIFT) | \
232+
(DT_INST_ENUM_IDX(n, led_pw) << MAX30101_SPO2_PW_SHIFT), \
233+
.led_pa = DT_INST_PROP(n, led_pa), \
234+
.slot = MAX30101_SLOT_CFG(n), \
235+
}; \
236+
static struct max30101_data max30101_data_##n; \
237+
SENSOR_DEVICE_DT_INST_DEFINE(n, max30101_init, NULL, &max30101_data_##n, \
238+
&max30101_config_##n, POST_KERNEL, \
239+
CONFIG_SENSOR_INIT_PRIORITY, &max30101_driver_api);
240+
241+
DT_INST_FOREACH_STATUS_OKAY(MAX30101_INIT)

0 commit comments

Comments
 (0)