mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-22 09:22:37 +00:00
87aec56e27
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>
192 lines
5.1 KiB
C
192 lines
5.1 KiB
C
/*
|
|
* AFE440X Heart Rate Monitors and Low-Cost Pulse Oximeters
|
|
*
|
|
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
|
|
* Andrew F. Davis <afd@ti.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*/
|
|
|
|
#ifndef _AFE440X_H
|
|
#define _AFE440X_H
|
|
|
|
/* AFE440X registers */
|
|
#define AFE440X_CONTROL0 0x00
|
|
#define AFE440X_LED2STC 0x01
|
|
#define AFE440X_LED2ENDC 0x02
|
|
#define AFE440X_LED1LEDSTC 0x03
|
|
#define AFE440X_LED1LEDENDC 0x04
|
|
#define AFE440X_ALED2STC 0x05
|
|
#define AFE440X_ALED2ENDC 0x06
|
|
#define AFE440X_LED1STC 0x07
|
|
#define AFE440X_LED1ENDC 0x08
|
|
#define AFE440X_LED2LEDSTC 0x09
|
|
#define AFE440X_LED2LEDENDC 0x0a
|
|
#define AFE440X_ALED1STC 0x0b
|
|
#define AFE440X_ALED1ENDC 0x0c
|
|
#define AFE440X_LED2CONVST 0x0d
|
|
#define AFE440X_LED2CONVEND 0x0e
|
|
#define AFE440X_ALED2CONVST 0x0f
|
|
#define AFE440X_ALED2CONVEND 0x10
|
|
#define AFE440X_LED1CONVST 0x11
|
|
#define AFE440X_LED1CONVEND 0x12
|
|
#define AFE440X_ALED1CONVST 0x13
|
|
#define AFE440X_ALED1CONVEND 0x14
|
|
#define AFE440X_ADCRSTSTCT0 0x15
|
|
#define AFE440X_ADCRSTENDCT0 0x16
|
|
#define AFE440X_ADCRSTSTCT1 0x17
|
|
#define AFE440X_ADCRSTENDCT1 0x18
|
|
#define AFE440X_ADCRSTSTCT2 0x19
|
|
#define AFE440X_ADCRSTENDCT2 0x1a
|
|
#define AFE440X_ADCRSTSTCT3 0x1b
|
|
#define AFE440X_ADCRSTENDCT3 0x1c
|
|
#define AFE440X_PRPCOUNT 0x1d
|
|
#define AFE440X_CONTROL1 0x1e
|
|
#define AFE440X_LEDCNTRL 0x22
|
|
#define AFE440X_CONTROL2 0x23
|
|
#define AFE440X_ALARM 0x29
|
|
#define AFE440X_LED2VAL 0x2a
|
|
#define AFE440X_ALED2VAL 0x2b
|
|
#define AFE440X_LED1VAL 0x2c
|
|
#define AFE440X_ALED1VAL 0x2d
|
|
#define AFE440X_LED2_ALED2VAL 0x2e
|
|
#define AFE440X_LED1_ALED1VAL 0x2f
|
|
#define AFE440X_CONTROL3 0x31
|
|
#define AFE440X_PDNCYCLESTC 0x32
|
|
#define AFE440X_PDNCYCLEENDC 0x33
|
|
|
|
/* CONTROL0 register fields */
|
|
#define AFE440X_CONTROL0_REG_READ BIT(0)
|
|
#define AFE440X_CONTROL0_TM_COUNT_RST BIT(1)
|
|
#define AFE440X_CONTROL0_SW_RESET BIT(3)
|
|
|
|
/* CONTROL1 register fields */
|
|
#define AFE440X_CONTROL1_TIMEREN BIT(8)
|
|
|
|
/* TIAGAIN register fields */
|
|
#define AFE440X_TIAGAIN_ENSEPGAIN_MASK BIT(15)
|
|
#define AFE440X_TIAGAIN_ENSEPGAIN_SHIFT 15
|
|
|
|
/* CONTROL2 register fields */
|
|
#define AFE440X_CONTROL2_PDN_AFE BIT(0)
|
|
#define AFE440X_CONTROL2_PDN_RX BIT(1)
|
|
#define AFE440X_CONTROL2_DYNAMIC4 BIT(3)
|
|
#define AFE440X_CONTROL2_DYNAMIC3 BIT(4)
|
|
#define AFE440X_CONTROL2_DYNAMIC2 BIT(14)
|
|
#define AFE440X_CONTROL2_DYNAMIC1 BIT(20)
|
|
|
|
/* CONTROL3 register fields */
|
|
#define AFE440X_CONTROL3_CLKDIV GENMASK(2, 0)
|
|
|
|
/* CONTROL0 values */
|
|
#define AFE440X_CONTROL0_WRITE 0x0
|
|
#define AFE440X_CONTROL0_READ 0x1
|
|
|
|
struct afe440x_reg_info {
|
|
unsigned int reg;
|
|
unsigned int offreg;
|
|
unsigned int shift;
|
|
unsigned int mask;
|
|
};
|
|
|
|
#define AFE440X_REG_INFO(_reg, _offreg, _sm) \
|
|
{ \
|
|
.reg = _reg, \
|
|
.offreg = _offreg, \
|
|
.shift = _sm ## _SHIFT, \
|
|
.mask = _sm ## _MASK, \
|
|
}
|
|
|
|
#define AFE440X_INTENSITY_CHAN(_index, _name, _mask) \
|
|
{ \
|
|
.type = IIO_INTENSITY, \
|
|
.channel = _index, \
|
|
.address = _index, \
|
|
.scan_index = _index, \
|
|
.scan_type = { \
|
|
.sign = 's', \
|
|
.realbits = 24, \
|
|
.storagebits = 32, \
|
|
.endianness = IIO_CPU, \
|
|
}, \
|
|
.extend_name = _name, \
|
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
|
_mask, \
|
|
}
|
|
|
|
#define AFE440X_CURRENT_CHAN(_index, _name) \
|
|
{ \
|
|
.type = IIO_CURRENT, \
|
|
.channel = _index, \
|
|
.address = _index, \
|
|
.scan_index = _index, \
|
|
.extend_name = _name, \
|
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
|
BIT(IIO_CHAN_INFO_SCALE), \
|
|
.output = true, \
|
|
}
|
|
|
|
enum afe440x_reg_type {
|
|
SIMPLE,
|
|
RESISTANCE,
|
|
CAPACITANCE,
|
|
};
|
|
|
|
struct afe440x_val_table {
|
|
int integer;
|
|
int fract;
|
|
};
|
|
|
|
#define AFE440X_TABLE_ATTR(_name, _table) \
|
|
static ssize_t _name ## _show(struct device *dev, \
|
|
struct device_attribute *attr, char *buf) \
|
|
{ \
|
|
ssize_t len = 0; \
|
|
int i; \
|
|
\
|
|
for (i = 0; i < ARRAY_SIZE(_table); i++) \
|
|
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ", \
|
|
_table[i].integer, \
|
|
_table[i].fract); \
|
|
\
|
|
buf[len - 1] = '\n'; \
|
|
\
|
|
return len; \
|
|
} \
|
|
static DEVICE_ATTR_RO(_name)
|
|
|
|
struct afe440x_attr {
|
|
struct device_attribute dev_attr;
|
|
unsigned int reg;
|
|
unsigned int shift;
|
|
unsigned int mask;
|
|
enum afe440x_reg_type type;
|
|
const struct afe440x_val_table *val_table;
|
|
unsigned int table_size;
|
|
};
|
|
|
|
#define to_afe440x_attr(_dev_attr) \
|
|
container_of(_dev_attr, struct afe440x_attr, dev_attr)
|
|
|
|
#define AFE440X_ATTR(_name, _reg, _field, _type, _table, _size) \
|
|
struct afe440x_attr afe440x_attr_##_name = { \
|
|
.dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR), \
|
|
afe440x_show_register, \
|
|
afe440x_store_register), \
|
|
.reg = _reg, \
|
|
.shift = _field ## _SHIFT, \
|
|
.mask = _field ## _MASK, \
|
|
.type = _type, \
|
|
.val_table = _table, \
|
|
.table_size = _size, \
|
|
}
|
|
|
|
#endif /* _AFE440X_H */
|