aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorAndrew F. Davis <afd@ti.com>2016-02-02 12:50:44 -0500
committerJonathan Cameron <jic23@kernel.org>2016-02-06 13:57:09 -0500
commit87aec56e27efac98b7a0abe93258687716bf0b1e (patch)
treeeb73a4e2e2912212fa5321f0cea850b4790d72a9 /drivers/iio
parent380f6ff5495e8008775078e62e748c7e8f099270 (diff)
iio: health: Add driver for the TI AFE4404 heart monitor
Add driver for the TI AFE4404 heart rate monitor and pulse oximeter. This device detects reflected LED light fluctuations and presents an ADC value to the user space for further signal processing. Datasheet: http://www.ti.com/product/AFE4404/datasheet Signed-off-by: Andrew F. Davis <afd@ti.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/health/Kconfig19
-rw-r--r--drivers/iio/health/Makefile1
-rw-r--r--drivers/iio/health/afe4404.c679
-rw-r--r--drivers/iio/health/afe440x.h191
4 files changed, 889 insertions, 1 deletions
diff --git a/drivers/iio/health/Kconfig b/drivers/iio/health/Kconfig
index a647679da805..632a14b7dd6f 100644
--- a/drivers/iio/health/Kconfig
+++ b/drivers/iio/health/Kconfig
@@ -3,7 +3,22 @@
3# 3#
4# When adding new entries keep the list in alphabetical order 4# When adding new entries keep the list in alphabetical order
5 5
6menu "Health sensors" 6menu "Health Sensors"
7
8menu "Heart Rate Monitors"
9
10config AFE4404
11 tristate "TI AFE4404 heart rate and pulse oximeter sensor"
12 depends on I2C
13 select REGMAP_I2C
14 select IIO_BUFFER
15 select IIO_TRIGGERED_BUFFER
16 help
17 Say yes to choose the Texas Instruments AFE4404
18 heart rate monitor and low-cost pulse oximeter.
19
20 To compile this driver as a module, choose M here: the
21 module will be called afe4404.
7 22
8config MAX30100 23config MAX30100
9 tristate "MAX30100 heart rate and pulse oximeter sensor" 24 tristate "MAX30100 heart rate and pulse oximeter sensor"
@@ -19,3 +34,5 @@ config MAX30100
19 module will be called max30100. 34 module will be called max30100.
20 35
21endmenu 36endmenu
37
38endmenu
diff --git a/drivers/iio/health/Makefile b/drivers/iio/health/Makefile
index 7c475d7faad8..b37c0d5e07b8 100644
--- a/drivers/iio/health/Makefile
+++ b/drivers/iio/health/Makefile
@@ -4,4 +4,5 @@
4 4
5# When adding new entries keep the list in alphabetical order 5# When adding new entries keep the list in alphabetical order
6 6
7obj-$(CONFIG_AFE4404) += afe4404.o
7obj-$(CONFIG_MAX30100) += max30100.o 8obj-$(CONFIG_MAX30100) += max30100.o
diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c
new file mode 100644
index 000000000000..0759268f37e0
--- /dev/null
+++ b/drivers/iio/health/afe4404.c
@@ -0,0 +1,679 @@
1/*
2 * AFE4404 Heart Rate Monitors and Low-Cost Pulse Oximeters
3 *
4 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
5 * Andrew F. Davis <afd@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
16
17#include <linux/device.h>
18#include <linux/err.h>
19#include <linux/interrupt.h>
20#include <linux/i2c.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/regmap.h>
24#include <linux/sysfs.h>
25#include <linux/regulator/consumer.h>
26
27#include <linux/iio/iio.h>
28#include <linux/iio/sysfs.h>
29#include <linux/iio/buffer.h>
30#include <linux/iio/trigger.h>
31#include <linux/iio/triggered_buffer.h>
32#include <linux/iio/trigger_consumer.h>
33
34#include "afe440x.h"
35
36#define AFE4404_DRIVER_NAME "afe4404"
37
38/* AFE4404 registers */
39#define AFE4404_TIA_GAIN_SEP 0x20
40#define AFE4404_TIA_GAIN 0x21
41#define AFE4404_PROG_TG_STC 0x34
42#define AFE4404_PROG_TG_ENDC 0x35
43#define AFE4404_LED3LEDSTC 0x36
44#define AFE4404_LED3LEDENDC 0x37
45#define AFE4404_CLKDIV_PRF 0x39
46#define AFE4404_OFFDAC 0x3a
47#define AFE4404_DEC 0x3d
48#define AFE4404_AVG_LED2_ALED2VAL 0x3f
49#define AFE4404_AVG_LED1_ALED1VAL 0x40
50
51/* AFE4404 GAIN register fields */
52#define AFE4404_TIA_GAIN_RES_MASK GENMASK(2, 0)
53#define AFE4404_TIA_GAIN_RES_SHIFT 0
54#define AFE4404_TIA_GAIN_CAP_MASK GENMASK(5, 3)
55#define AFE4404_TIA_GAIN_CAP_SHIFT 3
56
57/* AFE4404 LEDCNTRL register fields */
58#define AFE4404_LEDCNTRL_ILED1_MASK GENMASK(5, 0)
59#define AFE4404_LEDCNTRL_ILED1_SHIFT 0
60#define AFE4404_LEDCNTRL_ILED2_MASK GENMASK(11, 6)
61#define AFE4404_LEDCNTRL_ILED2_SHIFT 6
62#define AFE4404_LEDCNTRL_ILED3_MASK GENMASK(17, 12)
63#define AFE4404_LEDCNTRL_ILED3_SHIFT 12
64
65/* AFE4404 CONTROL2 register fields */
66#define AFE440X_CONTROL2_ILED_2X_MASK BIT(17)
67#define AFE440X_CONTROL2_ILED_2X_SHIFT 17
68
69/* AFE4404 CONTROL3 register fields */
70#define AFE440X_CONTROL3_OSC_ENABLE BIT(9)
71
72/* AFE4404 OFFDAC register current fields */
73#define AFE4404_OFFDAC_CURR_LED1_MASK GENMASK(9, 5)
74#define AFE4404_OFFDAC_CURR_LED1_SHIFT 5
75#define AFE4404_OFFDAC_CURR_LED2_MASK GENMASK(19, 15)
76#define AFE4404_OFFDAC_CURR_LED2_SHIFT 15
77#define AFE4404_OFFDAC_CURR_LED3_MASK GENMASK(4, 0)
78#define AFE4404_OFFDAC_CURR_LED3_SHIFT 0
79#define AFE4404_OFFDAC_CURR_ALED1_MASK GENMASK(14, 10)
80#define AFE4404_OFFDAC_CURR_ALED1_SHIFT 10
81#define AFE4404_OFFDAC_CURR_ALED2_MASK GENMASK(4, 0)
82#define AFE4404_OFFDAC_CURR_ALED2_SHIFT 0
83
84/* AFE4404 NULL fields */
85#define NULL_MASK 0
86#define NULL_SHIFT 0
87
88/* AFE4404 TIA_GAIN_CAP values */
89#define AFE4404_TIA_GAIN_CAP_5_P 0x0
90#define AFE4404_TIA_GAIN_CAP_2_5_P 0x1
91#define AFE4404_TIA_GAIN_CAP_10_P 0x2
92#define AFE4404_TIA_GAIN_CAP_7_5_P 0x3
93#define AFE4404_TIA_GAIN_CAP_20_P 0x4
94#define AFE4404_TIA_GAIN_CAP_17_5_P 0x5
95#define AFE4404_TIA_GAIN_CAP_25_P 0x6
96#define AFE4404_TIA_GAIN_CAP_22_5_P 0x7
97
98/* AFE4404 TIA_GAIN_RES values */
99#define AFE4404_TIA_GAIN_RES_500_K 0x0
100#define AFE4404_TIA_GAIN_RES_250_K 0x1
101#define AFE4404_TIA_GAIN_RES_100_K 0x2
102#define AFE4404_TIA_GAIN_RES_50_K 0x3
103#define AFE4404_TIA_GAIN_RES_25_K 0x4
104#define AFE4404_TIA_GAIN_RES_10_K 0x5
105#define AFE4404_TIA_GAIN_RES_1_M 0x6
106#define AFE4404_TIA_GAIN_RES_2_M 0x7
107
108/**
109 * struct afe4404_data
110 * @dev - Device structure
111 * @regmap - Register map of the device
112 * @regulator - Pointer to the regulator for the IC
113 * @trig - IIO trigger for this device
114 * @irq - ADC_RDY line interrupt number
115 */
116struct afe4404_data {
117 struct device *dev;
118 struct regmap *regmap;
119 struct regulator *regulator;
120 struct iio_trigger *trig;
121 int irq;
122};
123
124enum afe4404_chan_id {
125 LED1,
126 ALED1,
127 LED2,
128 ALED2,
129 LED3,
130 LED1_ALED1,
131 LED2_ALED2,
132 ILED1,
133 ILED2,
134 ILED3,
135};
136
137static const struct afe440x_reg_info afe4404_reg_info[] = {
138 [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1),
139 [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1),
140 [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2),
141 [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2),
142 [LED3] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL),
143 [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL),
144 [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL),
145 [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1),
146 [ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED2),
147 [ILED3] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED3),
148};
149
150static const struct iio_chan_spec afe4404_channels[] = {
151 /* ADC values */
152 AFE440X_INTENSITY_CHAN(LED1, "led1", BIT(IIO_CHAN_INFO_OFFSET)),
153 AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", BIT(IIO_CHAN_INFO_OFFSET)),
154 AFE440X_INTENSITY_CHAN(LED2, "led2", BIT(IIO_CHAN_INFO_OFFSET)),
155 AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", BIT(IIO_CHAN_INFO_OFFSET)),
156 AFE440X_INTENSITY_CHAN(LED3, "led3", BIT(IIO_CHAN_INFO_OFFSET)),
157 AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0),
158 AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0),
159 /* LED current */
160 AFE440X_CURRENT_CHAN(ILED1, "led1"),
161 AFE440X_CURRENT_CHAN(ILED2, "led2"),
162 AFE440X_CURRENT_CHAN(ILED3, "led3"),
163};
164
165static const struct afe440x_val_table afe4404_res_table[] = {
166 { .integer = 500000, .fract = 0 },
167 { .integer = 250000, .fract = 0 },
168 { .integer = 100000, .fract = 0 },
169 { .integer = 50000, .fract = 0 },
170 { .integer = 25000, .fract = 0 },
171 { .integer = 10000, .fract = 0 },
172 { .integer = 1000000, .fract = 0 },
173 { .integer = 2000000, .fract = 0 },
174};
175AFE440X_TABLE_ATTR(tia_resistance_available, afe4404_res_table);
176
177static const struct afe440x_val_table afe4404_cap_table[] = {
178 { .integer = 0, .fract = 5000 },
179 { .integer = 0, .fract = 2500 },
180 { .integer = 0, .fract = 10000 },
181 { .integer = 0, .fract = 7500 },
182 { .integer = 0, .fract = 20000 },
183 { .integer = 0, .fract = 17500 },
184 { .integer = 0, .fract = 25000 },
185 { .integer = 0, .fract = 22500 },
186};
187AFE440X_TABLE_ATTR(tia_capacitance_available, afe4404_cap_table);
188
189static ssize_t afe440x_show_register(struct device *dev,
190 struct device_attribute *attr,
191 char *buf)
192{
193 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
194 struct afe4404_data *afe = iio_priv(indio_dev);
195 struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr);
196 unsigned int reg_val, type;
197 int vals[2];
198 int ret, val_len;
199
200 ret = regmap_read(afe->regmap, afe440x_attr->reg, &reg_val);
201 if (ret)
202 return ret;
203
204 reg_val &= afe440x_attr->mask;
205 reg_val >>= afe440x_attr->shift;
206
207 switch (afe440x_attr->type) {
208 case SIMPLE:
209 type = IIO_VAL_INT;
210 val_len = 1;
211 vals[0] = reg_val;
212 break;
213 case RESISTANCE:
214 case CAPACITANCE:
215 type = IIO_VAL_INT_PLUS_MICRO;
216 val_len = 2;
217 if (reg_val < afe440x_attr->table_size) {
218 vals[0] = afe440x_attr->val_table[reg_val].integer;
219 vals[1] = afe440x_attr->val_table[reg_val].fract;
220 break;
221 }
222 return -EINVAL;
223 default:
224 return -EINVAL;
225 }
226
227 return iio_format_value(buf, type, val_len, vals);
228}
229
230static ssize_t afe440x_store_register(struct device *dev,
231 struct device_attribute *attr,
232 const char *buf, size_t count)
233{
234 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
235 struct afe4404_data *afe = iio_priv(indio_dev);
236 struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr);
237 int val, integer, fract, ret;
238
239 ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract);
240 if (ret)
241 return ret;
242
243 switch (afe440x_attr->type) {
244 case SIMPLE:
245 val = integer;
246 break;
247 case RESISTANCE:
248 case CAPACITANCE:
249 for (val = 0; val < afe440x_attr->table_size; val++)
250 if (afe440x_attr->val_table[val].integer == integer &&
251 afe440x_attr->val_table[val].fract == fract)
252 break;
253 if (val == afe440x_attr->table_size)
254 return -EINVAL;
255 break;
256 default:
257 return -EINVAL;
258 }
259
260 ret = regmap_update_bits(afe->regmap, afe440x_attr->reg,
261 afe440x_attr->mask,
262 (val << afe440x_attr->shift));
263 if (ret)
264 return ret;
265
266 return count;
267}
268
269static AFE440X_ATTR(tia_separate_en, AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0);
270
271static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table));
272static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table));
273
274static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table));
275static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table));
276
277static struct attribute *afe440x_attributes[] = {
278 &afe440x_attr_tia_separate_en.dev_attr.attr,
279 &afe440x_attr_tia_resistance1.dev_attr.attr,
280 &afe440x_attr_tia_capacitance1.dev_attr.attr,
281 &afe440x_attr_tia_resistance2.dev_attr.attr,
282 &afe440x_attr_tia_capacitance2.dev_attr.attr,
283 &dev_attr_tia_resistance_available.attr,
284 &dev_attr_tia_capacitance_available.attr,
285 NULL
286};
287
288static const struct attribute_group afe440x_attribute_group = {
289 .attrs = afe440x_attributes
290};
291
292static int afe4404_read_raw(struct iio_dev *indio_dev,
293 struct iio_chan_spec const *chan,
294 int *val, int *val2, long mask)
295{
296 struct afe4404_data *afe = iio_priv(indio_dev);
297 const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address];
298 int ret;
299
300 switch (chan->type) {
301 case IIO_INTENSITY:
302 switch (mask) {
303 case IIO_CHAN_INFO_RAW:
304 ret = regmap_read(afe->regmap, reg_info.reg, val);
305 if (ret)
306 return ret;
307 return IIO_VAL_INT;
308 case IIO_CHAN_INFO_OFFSET:
309 ret = regmap_read(afe->regmap, reg_info.offreg,
310 val);
311 if (ret)
312 return ret;
313 *val &= reg_info.mask;
314 *val >>= reg_info.shift;
315 return IIO_VAL_INT;
316 }
317 break;
318 case IIO_CURRENT:
319 switch (mask) {
320 case IIO_CHAN_INFO_RAW:
321 ret = regmap_read(afe->regmap, reg_info.reg, val);
322 if (ret)
323 return ret;
324 *val &= reg_info.mask;
325 *val >>= reg_info.shift;
326 return IIO_VAL_INT;
327 case IIO_CHAN_INFO_SCALE:
328 *val = 0;
329 *val2 = 800000;
330 return IIO_VAL_INT_PLUS_MICRO;
331 }
332 break;
333 default:
334 break;
335 }
336
337 return -EINVAL;
338}
339
340static int afe4404_write_raw(struct iio_dev *indio_dev,
341 struct iio_chan_spec const *chan,
342 int val, int val2, long mask)
343{
344 struct afe4404_data *afe = iio_priv(indio_dev);
345 const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address];
346
347 switch (chan->type) {
348 case IIO_INTENSITY:
349 switch (mask) {
350 case IIO_CHAN_INFO_OFFSET:
351 return regmap_update_bits(afe->regmap,
352 reg_info.offreg,
353 reg_info.mask,
354 (val << reg_info.shift));
355 }
356 break;
357 case IIO_CURRENT:
358 switch (mask) {
359 case IIO_CHAN_INFO_RAW:
360 return regmap_update_bits(afe->regmap,
361 reg_info.reg,
362 reg_info.mask,
363 (val << reg_info.shift));
364 }
365 break;
366 default:
367 break;
368 }
369
370 return -EINVAL;
371}
372
373static const struct iio_info afe4404_iio_info = {
374 .attrs = &afe440x_attribute_group,
375 .read_raw = afe4404_read_raw,
376 .write_raw = afe4404_write_raw,
377 .driver_module = THIS_MODULE,
378};
379
380static irqreturn_t afe4404_trigger_handler(int irq, void *private)
381{
382 struct iio_poll_func *pf = private;
383 struct iio_dev *indio_dev = pf->indio_dev;
384 struct afe4404_data *afe = iio_priv(indio_dev);
385 int ret, bit, i = 0;
386 s32 buffer[10];
387
388 for_each_set_bit(bit, indio_dev->active_scan_mask,
389 indio_dev->masklength) {
390 ret = regmap_read(afe->regmap, afe4404_reg_info[bit].reg,
391 &buffer[i++]);
392 if (ret)
393 goto err;
394 }
395
396 iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp);
397err:
398 iio_trigger_notify_done(indio_dev->trig);
399
400 return IRQ_HANDLED;
401}
402
403static const struct iio_trigger_ops afe4404_trigger_ops = {
404 .owner = THIS_MODULE,
405};
406
407/* Default timings from data-sheet */
408#define AFE4404_TIMING_PAIRS \
409 { AFE440X_PRPCOUNT, 39999 }, \
410 { AFE440X_LED2LEDSTC, 0 }, \
411 { AFE440X_LED2LEDENDC, 398 }, \
412 { AFE440X_LED2STC, 80 }, \
413 { AFE440X_LED2ENDC, 398 }, \
414 { AFE440X_ADCRSTSTCT0, 5600 }, \
415 { AFE440X_ADCRSTENDCT0, 5606 }, \
416 { AFE440X_LED2CONVST, 5607 }, \
417 { AFE440X_LED2CONVEND, 6066 }, \
418 { AFE4404_LED3LEDSTC, 400 }, \
419 { AFE4404_LED3LEDENDC, 798 }, \
420 { AFE440X_ALED2STC, 480 }, \
421 { AFE440X_ALED2ENDC, 798 }, \
422 { AFE440X_ADCRSTSTCT1, 6068 }, \
423 { AFE440X_ADCRSTENDCT1, 6074 }, \
424 { AFE440X_ALED2CONVST, 6075 }, \
425 { AFE440X_ALED2CONVEND, 6534 }, \
426 { AFE440X_LED1LEDSTC, 800 }, \
427 { AFE440X_LED1LEDENDC, 1198 }, \
428 { AFE440X_LED1STC, 880 }, \
429 { AFE440X_LED1ENDC, 1198 }, \
430 { AFE440X_ADCRSTSTCT2, 6536 }, \
431 { AFE440X_ADCRSTENDCT2, 6542 }, \
432 { AFE440X_LED1CONVST, 6543 }, \
433 { AFE440X_LED1CONVEND, 7003 }, \
434 { AFE440X_ALED1STC, 1280 }, \
435 { AFE440X_ALED1ENDC, 1598 }, \
436 { AFE440X_ADCRSTSTCT3, 7005 }, \
437 { AFE440X_ADCRSTENDCT3, 7011 }, \
438 { AFE440X_ALED1CONVST, 7012 }, \
439 { AFE440X_ALED1CONVEND, 7471 }, \
440 { AFE440X_PDNCYCLESTC, 7671 }, \
441 { AFE440X_PDNCYCLEENDC, 39199 }
442
443static const struct reg_sequence afe4404_reg_sequences[] = {
444 AFE4404_TIMING_PAIRS,
445 { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN },
446 { AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES_50_K },
447 { AFE440X_LEDCNTRL, (0xf << AFE4404_LEDCNTRL_ILED1_SHIFT) |
448 (0x3 << AFE4404_LEDCNTRL_ILED2_SHIFT) |
449 (0x3 << AFE4404_LEDCNTRL_ILED3_SHIFT) },
450 { AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE },
451};
452
453static const struct regmap_range afe4404_yes_ranges[] = {
454 regmap_reg_range(AFE440X_LED2VAL, AFE440X_LED1_ALED1VAL),
455 regmap_reg_range(AFE4404_AVG_LED2_ALED2VAL, AFE4404_AVG_LED1_ALED1VAL),
456};
457
458static const struct regmap_access_table afe4404_volatile_table = {
459 .yes_ranges = afe4404_yes_ranges,
460 .n_yes_ranges = ARRAY_SIZE(afe4404_yes_ranges),
461};
462
463static const struct regmap_config afe4404_regmap_config = {
464 .reg_bits = 8,
465 .val_bits = 24,
466
467 .max_register = AFE4404_AVG_LED1_ALED1VAL,
468 .cache_type = REGCACHE_RBTREE,
469 .volatile_table = &afe4404_volatile_table,
470};
471
472#ifdef CONFIG_OF
473static const struct of_device_id afe4404_of_match[] = {
474 { .compatible = "ti,afe4404", },
475 { /* sentinel */ }
476};
477MODULE_DEVICE_TABLE(of, afe4404_of_match);
478#endif
479
480static int afe4404_suspend(struct device *dev)
481{
482 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
483 struct afe4404_data *afe = iio_priv(indio_dev);
484 int ret;
485
486 ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
487 AFE440X_CONTROL2_PDN_AFE,
488 AFE440X_CONTROL2_PDN_AFE);
489 if (ret)
490 return ret;
491
492 ret = regulator_disable(afe->regulator);
493 if (ret) {
494 dev_err(dev, "Unable to disable regulator\n");
495 return ret;
496 }
497
498 return 0;
499}
500
501static int afe4404_resume(struct device *dev)
502{
503 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
504 struct afe4404_data *afe = iio_priv(indio_dev);
505 int ret;
506
507 ret = regulator_enable(afe->regulator);
508 if (ret) {
509 dev_err(dev, "Unable to enable regulator\n");
510 return ret;
511 }
512
513 ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2,
514 AFE440X_CONTROL2_PDN_AFE, 0);
515 if (ret)
516 return ret;
517
518 return 0;
519}
520
521static SIMPLE_DEV_PM_OPS(afe4404_pm_ops, afe4404_suspend, afe4404_resume);
522
523static int afe4404_probe(struct i2c_client *client,
524 const struct i2c_device_id *id)
525{
526 struct iio_dev *indio_dev;
527 struct afe4404_data *afe;
528 int ret;
529
530 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*afe));
531 if (!indio_dev)
532 return -ENOMEM;
533
534 afe = iio_priv(indio_dev);
535 i2c_set_clientdata(client, indio_dev);
536
537 afe->dev = &client->dev;
538 afe->irq = client->irq;
539
540 afe->regmap = devm_regmap_init_i2c(client, &afe4404_regmap_config);
541 if (IS_ERR(afe->regmap)) {
542 dev_err(afe->dev, "Unable to allocate register map\n");
543 return PTR_ERR(afe->regmap);
544 }
545
546 afe->regulator = devm_regulator_get(afe->dev, "tx_sup");
547 if (IS_ERR(afe->regulator)) {
548 dev_err(afe->dev, "Unable to get regulator\n");
549 return PTR_ERR(afe->regulator);
550 }
551 ret = regulator_enable(afe->regulator);
552 if (ret) {
553 dev_err(afe->dev, "Unable to enable regulator\n");
554 return ret;
555 }
556
557 ret = regmap_write(afe->regmap, AFE440X_CONTROL0,
558 AFE440X_CONTROL0_SW_RESET);
559 if (ret) {
560 dev_err(afe->dev, "Unable to reset device\n");
561 goto disable_reg;
562 }
563
564 ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences,
565 ARRAY_SIZE(afe4404_reg_sequences));
566 if (ret) {
567 dev_err(afe->dev, "Unable to set register defaults\n");
568 goto disable_reg;
569 }
570
571 indio_dev->modes = INDIO_DIRECT_MODE;
572 indio_dev->dev.parent = afe->dev;
573 indio_dev->channels = afe4404_channels;
574 indio_dev->num_channels = ARRAY_SIZE(afe4404_channels);
575 indio_dev->name = AFE4404_DRIVER_NAME;
576 indio_dev->info = &afe4404_iio_info;
577
578 if (afe->irq > 0) {
579 afe->trig = devm_iio_trigger_alloc(afe->dev,
580 "%s-dev%d",
581 indio_dev->name,
582 indio_dev->id);
583 if (!afe->trig) {
584 dev_err(afe->dev, "Unable to allocate IIO trigger\n");
585 ret = -ENOMEM;
586 goto disable_reg;
587 }
588
589 iio_trigger_set_drvdata(afe->trig, indio_dev);
590
591 afe->trig->ops = &afe4404_trigger_ops;
592 afe->trig->dev.parent = afe->dev;
593
594 ret = iio_trigger_register(afe->trig);
595 if (ret) {
596 dev_err(afe->dev, "Unable to register IIO trigger\n");
597 goto disable_reg;
598 }
599
600 ret = devm_request_threaded_irq(afe->dev, afe->irq,
601 iio_trigger_generic_data_rdy_poll,
602 NULL, IRQF_ONESHOT,
603 AFE4404_DRIVER_NAME,
604 afe->trig);
605 if (ret) {
606 dev_err(afe->dev, "Unable to request IRQ\n");
607 goto disable_reg;
608 }
609 }
610
611 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
612 afe4404_trigger_handler, NULL);
613 if (ret) {
614 dev_err(afe->dev, "Unable to setup buffer\n");
615 goto unregister_trigger;
616 }
617
618 ret = iio_device_register(indio_dev);
619 if (ret) {
620 dev_err(afe->dev, "Unable to register IIO device\n");
621 goto unregister_triggered_buffer;
622 }
623
624 return 0;
625
626unregister_triggered_buffer:
627 iio_triggered_buffer_cleanup(indio_dev);
628unregister_trigger:
629 if (afe->irq > 0)
630 iio_trigger_unregister(afe->trig);
631disable_reg:
632 regulator_disable(afe->regulator);
633
634 return ret;
635}
636
637static int afe4404_remove(struct i2c_client *client)
638{
639 struct iio_dev *indio_dev = i2c_get_clientdata(client);
640 struct afe4404_data *afe = iio_priv(indio_dev);
641 int ret;
642
643 iio_device_unregister(indio_dev);
644
645 iio_triggered_buffer_cleanup(indio_dev);
646
647 if (afe->irq > 0)
648 iio_trigger_unregister(afe->trig);
649
650 ret = regulator_disable(afe->regulator);
651 if (ret) {
652 dev_err(afe->dev, "Unable to disable regulator\n");
653 return ret;
654 }
655
656 return 0;
657}
658
659static const struct i2c_device_id afe4404_ids[] = {
660 { "afe4404", 0 },
661 { /* sentinel */ }
662};
663MODULE_DEVICE_TABLE(i2c, afe4404_ids);
664
665static struct i2c_driver afe4404_i2c_driver = {
666 .driver = {
667 .name = AFE4404_DRIVER_NAME,
668 .of_match_table = of_match_ptr(afe4404_of_match),
669 .pm = &afe4404_pm_ops,
670 },
671 .probe = afe4404_probe,
672 .remove = afe4404_remove,
673 .id_table = afe4404_ids,
674};
675module_i2c_driver(afe4404_i2c_driver);
676
677MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
678MODULE_DESCRIPTION("TI AFE4404 Heart Rate and Pulse Oximeter");
679MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/health/afe440x.h b/drivers/iio/health/afe440x.h
new file mode 100644
index 000000000000..c671ab78a23a
--- /dev/null
+++ b/drivers/iio/health/afe440x.h
@@ -0,0 +1,191 @@
1/*
2 * AFE440X Heart Rate Monitors and Low-Cost Pulse Oximeters
3 *
4 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
5 * Andrew F. Davis <afd@ti.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
16
17#ifndef _AFE440X_H
18#define _AFE440X_H
19
20/* AFE440X registers */
21#define AFE440X_CONTROL0 0x00
22#define AFE440X_LED2STC 0x01
23#define AFE440X_LED2ENDC 0x02
24#define AFE440X_LED1LEDSTC 0x03
25#define AFE440X_LED1LEDENDC 0x04
26#define AFE440X_ALED2STC 0x05
27#define AFE440X_ALED2ENDC 0x06
28#define AFE440X_LED1STC 0x07
29#define AFE440X_LED1ENDC 0x08
30#define AFE440X_LED2LEDSTC 0x09
31#define AFE440X_LED2LEDENDC 0x0a
32#define AFE440X_ALED1STC 0x0b
33#define AFE440X_ALED1ENDC 0x0c
34#define AFE440X_LED2CONVST 0x0d
35#define AFE440X_LED2CONVEND 0x0e
36#define AFE440X_ALED2CONVST 0x0f
37#define AFE440X_ALED2CONVEND 0x10
38#define AFE440X_LED1CONVST 0x11
39#define AFE440X_LED1CONVEND 0x12
40#define AFE440X_ALED1CONVST 0x13
41#define AFE440X_ALED1CONVEND 0x14
42#define AFE440X_ADCRSTSTCT0 0x15
43#define AFE440X_ADCRSTENDCT0 0x16
44#define AFE440X_ADCRSTSTCT1 0x17
45#define AFE440X_ADCRSTENDCT1 0x18
46#define AFE440X_ADCRSTSTCT2 0x19
47#define AFE440X_ADCRSTENDCT2 0x1a
48#define AFE440X_ADCRSTSTCT3 0x1b
49#define AFE440X_ADCRSTENDCT3 0x1c
50#define AFE440X_PRPCOUNT 0x1d
51#define AFE440X_CONTROL1 0x1e
52#define AFE440X_LEDCNTRL 0x22
53#define AFE440X_CONTROL2 0x23
54#define AFE440X_ALARM 0x29
55#define AFE440X_LED2VAL 0x2a
56#define AFE440X_ALED2VAL 0x2b
57#define AFE440X_LED1VAL 0x2c
58#define AFE440X_ALED1VAL 0x2d
59#define AFE440X_LED2_ALED2VAL 0x2e
60#define AFE440X_LED1_ALED1VAL 0x2f
61#define AFE440X_CONTROL3 0x31
62#define AFE440X_PDNCYCLESTC 0x32
63#define AFE440X_PDNCYCLEENDC 0x33
64
65/* CONTROL0 register fields */
66#define AFE440X_CONTROL0_REG_READ BIT(0)
67#define AFE440X_CONTROL0_TM_COUNT_RST BIT(1)
68#define AFE440X_CONTROL0_SW_RESET BIT(3)
69
70/* CONTROL1 register fields */
71#define AFE440X_CONTROL1_TIMEREN BIT(8)
72
73/* TIAGAIN register fields */
74#define AFE440X_TIAGAIN_ENSEPGAIN_MASK BIT(15)
75#define AFE440X_TIAGAIN_ENSEPGAIN_SHIFT 15
76
77/* CONTROL2 register fields */
78#define AFE440X_CONTROL2_PDN_AFE BIT(0)
79#define AFE440X_CONTROL2_PDN_RX BIT(1)
80#define AFE440X_CONTROL2_DYNAMIC4 BIT(3)
81#define AFE440X_CONTROL2_DYNAMIC3 BIT(4)
82#define AFE440X_CONTROL2_DYNAMIC2 BIT(14)
83#define AFE440X_CONTROL2_DYNAMIC1 BIT(20)
84
85/* CONTROL3 register fields */
86#define AFE440X_CONTROL3_CLKDIV GENMASK(2, 0)
87
88/* CONTROL0 values */
89#define AFE440X_CONTROL0_WRITE 0x0
90#define AFE440X_CONTROL0_READ 0x1
91
92struct afe440x_reg_info {
93 unsigned int reg;
94 unsigned int offreg;
95 unsigned int shift;
96 unsigned int mask;
97};
98
99#define AFE440X_REG_INFO(_reg, _offreg, _sm) \
100 { \
101 .reg = _reg, \
102 .offreg = _offreg, \
103 .shift = _sm ## _SHIFT, \
104 .mask = _sm ## _MASK, \
105 }
106
107#define AFE440X_INTENSITY_CHAN(_index, _name, _mask) \
108 { \
109 .type = IIO_INTENSITY, \
110 .channel = _index, \
111 .address = _index, \
112 .scan_index = _index, \
113 .scan_type = { \
114 .sign = 's', \
115 .realbits = 24, \
116 .storagebits = 32, \
117 .endianness = IIO_CPU, \
118 }, \
119 .extend_name = _name, \
120 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
121 _mask, \
122 }
123
124#define AFE440X_CURRENT_CHAN(_index, _name) \
125 { \
126 .type = IIO_CURRENT, \
127 .channel = _index, \
128 .address = _index, \
129 .scan_index = _index, \
130 .extend_name = _name, \
131 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
132 BIT(IIO_CHAN_INFO_SCALE), \
133 .output = true, \
134 }
135
136enum afe440x_reg_type {
137 SIMPLE,
138 RESISTANCE,
139 CAPACITANCE,
140};
141
142struct afe440x_val_table {
143 int integer;
144 int fract;
145};
146
147#define AFE440X_TABLE_ATTR(_name, _table) \
148static ssize_t _name ## _show(struct device *dev, \
149 struct device_attribute *attr, char *buf) \
150{ \
151 ssize_t len = 0; \
152 int i; \
153 \
154 for (i = 0; i < ARRAY_SIZE(_table); i++) \
155 len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ", \
156 _table[i].integer, \
157 _table[i].fract); \
158 \
159 buf[len - 1] = '\n'; \
160 \
161 return len; \
162} \
163static DEVICE_ATTR_RO(_name)
164
165struct afe440x_attr {
166 struct device_attribute dev_attr;
167 unsigned int reg;
168 unsigned int shift;
169 unsigned int mask;
170 enum afe440x_reg_type type;
171 const struct afe440x_val_table *val_table;
172 unsigned int table_size;
173};
174
175#define to_afe440x_attr(_dev_attr) \
176 container_of(_dev_attr, struct afe440x_attr, dev_attr)
177
178#define AFE440X_ATTR(_name, _reg, _field, _type, _table, _size) \
179 struct afe440x_attr afe440x_attr_##_name = { \
180 .dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR), \
181 afe440x_show_register, \
182 afe440x_store_register), \
183 .reg = _reg, \
184 .shift = _field ## _SHIFT, \
185 .mask = _field ## _MASK, \
186 .type = _type, \
187 .val_table = _table, \
188 .table_size = _size, \
189 }
190
191#endif /* _AFE440X_H */