mirror of
https://github.com/a52xq-dev/kernel.git
synced 2026-10-18 21:58:11 +07:00
First round of new IIO device support, features and cleanups for the 4.6 cycle.
Device Support
* ad5761
- new driver
* at91_sama5d2 ADC.
- new driver and MAINTAINERS entry.
- minor cleanups followed.
* atlas pH-SM
- new driver (this has possibly the prettiest data sheet I've ever seen)
* mcp3422
- mcp3425 ADC added.
* mcp4725
- mcp4726 DAC added.
* mma8452
- mma8451q accelerometer added.
* mpl115
- mpl115a1 added (a lot bigger than it seems as this is an SPI part whereas
previous parts were i2c).
* si7005
- Hoperf th02 (seems to be a repackaged part)
* si7020
- Hoperf th06 (seems to be a repackaged part)
New features
* Core
- IIO_PH type. Does what it says on the tin.
* max30100
- LED current configuration support.
* mcp320x
- more differential measurement combinations.
* mma8452
- free fall deteciton
- opt3001
- enable operation without a IRQ line.
- device tree docs. Somehow the original docs have disappeared down
a rabbit hole, so here is a new set.
* st-sensors
- Support active-low interrupts.
Cleanups and minor / not so minor reworks
* Documentation
- drop some defunct ABI from the docs in staging.
* presure / Kconfig
- white space cleanup.
* ad7150
- BIT macro usage
- Alignment fixes
* ad7192
- false indent fixed.
* ak8975
- constify the ak_def structures
* axp288
- drop a redundant double const.
* dht11
- substantial reliability improvements by being more tolerant
of missing start bits.
- simplify the decoding algorithm
* mma8452
- whitespace cleanup
* mpl115
- don't bother setting i2c_client_data as nothing uses it.
* mpu6050
- drop unused function parameter.
* opt3001
- extract integration time as constants.
- trivial refactoring.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAABCAAGBQJWr8HEAAoJEFSFNJnE9BaIIWMP/A6hJdAi3QOipB75QYBHL3R2
7fe7Bcd83i2to/Ohk9XirRwyP7kCqt1ZP7cnaIAevNxmwQ9fqIFgrxCK8BfF+lMk
60PXfEdinPk1rWguqEMwaYq1xVAOTgWYl8F4GVG3nGIvTHovAYaZW0UcTUl5Gz+l
WErEZQ5xgnf7e/29ds74eD3YaOti8E1mzhBLXFJH7lllsSMJttbp9Xb5J0QJrv4a
Ly8Ru5DBRGZYKi0VplFIjncKLZgX/VUUSPNL+NXtPnGD2Qp2zx0bJ3eIqNmeEYZl
isAGIc6l4XPXQLczyRaPbcQLobMxOHMP2uuXxY/OAbe2DX9/6ILcB2QigARAFHf2
7vVcx3JlxXUtwS/bPpZSd5hHrvjWLR7+gyuZTA4b/scV4+GvknMl8e6IIh4Ux3/T
d24V37bOIENrXCoyf81veap0xca6xQNSzCVuo8+1+QYqn6DxvoJw3p38Cmxb8eB8
7M+nQJP9SwLtbSUak8g1KVrtWBNsMrMGwoiuZq5SkK1PQTSXnSaJPTL0OoPoefNi
uIY5qD5FrUp9jlNbBP2M2E3CcG5CJcMElxyBgd7F5lEVxSWPOuyOcpJHIoCCCgIf
o6vwOYXXfD4ytv/E6jg+Bbv3ZYCylFhcoZOqPgTC/sOnSI9RwhJ6XdAg6VU8sv07
piH1AVWb91HKRN2dt2ZB
=fgTH
-----END PGP SIGNATURE-----
Merge tag 'iio-for-4.6a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
First round of new IIO device support, features and cleanups for the 4.6 cycle.
Device Support
* ad5761
- new driver
* at91_sama5d2 ADC.
- new driver and MAINTAINERS entry.
- minor cleanups followed.
* atlas pH-SM
- new driver (this has possibly the prettiest data sheet I've ever seen)
* mcp3422
- mcp3425 ADC added.
* mcp4725
- mcp4726 DAC added.
* mma8452
- mma8451q accelerometer added.
* mpl115
- mpl115a1 added (a lot bigger than it seems as this is an SPI part whereas
previous parts were i2c).
* si7005
- Hoperf th02 (seems to be a repackaged part)
* si7020
- Hoperf th06 (seems to be a repackaged part)
New features
* Core
- IIO_PH type. Does what it says on the tin.
* max30100
- LED current configuration support.
* mcp320x
- more differential measurement combinations.
* mma8452
- free fall deteciton
- opt3001
- enable operation without a IRQ line.
- device tree docs. Somehow the original docs have disappeared down
a rabbit hole, so here is a new set.
* st-sensors
- Support active-low interrupts.
Cleanups and minor / not so minor reworks
* Documentation
- drop some defunct ABI from the docs in staging.
* presure / Kconfig
- white space cleanup.
* ad7150
- BIT macro usage
- Alignment fixes
* ad7192
- false indent fixed.
* ak8975
- constify the ak_def structures
* axp288
- drop a redundant double const.
* dht11
- substantial reliability improvements by being more tolerant
of missing start bits.
- simplify the decoding algorithm
* mma8452
- whitespace cleanup
* mpl115
- don't bother setting i2c_client_data as nothing uses it.
* mpu6050
- drop unused function parameter.
* opt3001
- extract integration time as constants.
- trivial refactoring.
This commit is contained in:
commit
fec2f3335c
53 changed files with 2531 additions and 265 deletions
1
CREDITS
1
CREDITS
|
|
@ -3054,6 +3054,7 @@ D: PLX USB338x driver
|
|||
D: PCA9634 driver
|
||||
D: Option GTM671WFS
|
||||
D: Fintek F81216A
|
||||
D: AD5761 iio driver
|
||||
D: Various kernel hacks
|
||||
S: Qtechnology A/S
|
||||
S: Valby Langgade 142
|
||||
|
|
|
|||
|
|
@ -497,7 +497,9 @@ Description:
|
|||
6kohm_to_gnd: connected to ground via a 6kOhm resistor,
|
||||
20kohm_to_gnd: connected to ground via a 20kOhm resistor,
|
||||
100kohm_to_gnd: connected to ground via an 100kOhm resistor,
|
||||
125kohm_to_gnd: connected to ground via an 125kOhm resistor,
|
||||
500kohm_to_gnd: connected to ground via a 500kOhm resistor,
|
||||
640kohm_to_gnd: connected to ground via a 640kOhm resistor,
|
||||
three_state: left floating.
|
||||
For a list of available output power down options read
|
||||
outX_powerdown_mode_available. If Y is not present the
|
||||
|
|
@ -1491,3 +1493,10 @@ Description:
|
|||
This ABI is especially applicable for humidity sensors
|
||||
to heatup the device and get rid of any condensation
|
||||
in some humidity environment
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_ph_raw
|
||||
KernelVersion: 4.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Raw (unscaled no offset etc.) pH reading of a substance as a negative
|
||||
base-10 logarithm of hydrodium ions in a litre of water.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
Freescale MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC triaxial accelerometer
|
||||
Freescale MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC
|
||||
triaxial accelerometer
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should contain one of
|
||||
* "fsl,mma8451"
|
||||
* "fsl,mma8452"
|
||||
* "fsl,mma8453"
|
||||
* "fsl,mma8652"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
* AT91 SAMA5D2 Analog to Digital Converter (ADC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "atmel,sama5d2-adc".
|
||||
- reg: Should contain ADC registers location and length.
|
||||
- interrupts: Should contain the IRQ line for the ADC.
|
||||
- clocks: phandle to device clock.
|
||||
- clock-names: Must be "adc_clk".
|
||||
- vref-supply: Supply used as reference for conversions.
|
||||
- vddana-supply: Supply for the adc device.
|
||||
- atmel,min-sample-rate-hz: Minimum sampling rate, it depends on SoC.
|
||||
- atmel,max-sample-rate-hz: Maximum sampling rate, it depends on SoC.
|
||||
- atmel,startup-time-ms: Startup time expressed in ms, it depends on SoC.
|
||||
|
||||
Example:
|
||||
|
||||
adc: adc@fc030000 {
|
||||
compatible = "atmel,sama5d2-adc";
|
||||
reg = <0xfc030000 0x100>;
|
||||
interrupts = <40 IRQ_TYPE_LEVEL_HIGH 7>;
|
||||
clocks = <&adc_clk>;
|
||||
clock-names = "adc_clk";
|
||||
atmel,min-sample-rate-hz = <200000>;
|
||||
atmel,max-sample-rate-hz = <20000000>;
|
||||
atmel,startup-time-ms = <4>;
|
||||
vddana-supply = <&vdd_3v3_lp_reg>;
|
||||
vref-supply = <&vdd_3v3_lp_reg>;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ Required properties:
|
|||
"microchip,mcp3422" or
|
||||
"microchip,mcp3423" or
|
||||
"microchip,mcp3424" or
|
||||
"microchip,mcp3425" or
|
||||
"microchip,mcp3426" or
|
||||
"microchip,mcp3427" or
|
||||
"microchip,mcp3428"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
* Atlas Scientific pH-SM OEM sensor
|
||||
|
||||
http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: must be "atlas,ph-sm"
|
||||
- reg: the I2C address of the sensor
|
||||
- interrupt-parent: should be the phandle for the interrupt controller
|
||||
- interrupts: the sole interrupt generated by the device
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic interrupt client
|
||||
node bindings.
|
||||
|
||||
Example:
|
||||
|
||||
atlas@65 {
|
||||
compatible = "atlas,ph-sm";
|
||||
reg = <0x65>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 2>;
|
||||
};
|
||||
|
|
@ -11,11 +11,19 @@ Required properties:
|
|||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
|
||||
Optional properties:
|
||||
- maxim,led-current-microamp: configuration for LED current in microamperes
|
||||
while the engine is running. First indexed value is the configuration for
|
||||
the RED LED, and second value is for the IR LED.
|
||||
|
||||
Refer to the datasheet for the allowed current values.
|
||||
|
||||
Example:
|
||||
|
||||
max30100@057 {
|
||||
compatible = "maxim,max30100";
|
||||
reg = <57>;
|
||||
maxim,led-current-microamp = <24000 50000>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 2>;
|
||||
};
|
||||
|
|
|
|||
26
Documentation/devicetree/bindings/iio/light/opt3001.txt
Normal file
26
Documentation/devicetree/bindings/iio/light/opt3001.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
* Texas Instruments OPT3001 Ambient Light Sensor
|
||||
|
||||
The driver supports interrupt-driven and interrupt-less operation, depending
|
||||
on whether an interrupt property has been populated into the DT. Note that
|
||||
the optional generation of IIO events on rising/falling light threshold changes
|
||||
requires the use of interrupts. Without interrupts, only the simple reading
|
||||
of the current light value is supported through the IIO API.
|
||||
|
||||
http://www.ti.com/product/opt3001
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ti,opt3001"
|
||||
- reg: the I2C address of the sensor
|
||||
|
||||
Optional properties:
|
||||
- interrupt-parent: should be the phandle for the interrupt controller
|
||||
- interrupts: interrupt mapping for GPIO IRQ (configure for falling edge)
|
||||
|
||||
Example:
|
||||
|
||||
opt3001@44 {
|
||||
compatible = "ti,opt3001";
|
||||
reg = <0x44>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <28 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
|
|
@ -28,6 +28,7 @@ arm ARM Ltd.
|
|||
armadeus ARMadeus Systems SARL
|
||||
artesyn Artesyn Embedded Technologies Inc.
|
||||
asahi-kasei Asahi Kasei Corp.
|
||||
atlas Atlas Scientific LLC
|
||||
atmel Atmel Corporation
|
||||
auo AU Optronics Corporation
|
||||
avago Avago Technologies
|
||||
|
|
|
|||
|
|
@ -1945,6 +1945,12 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
|||
S: Supported
|
||||
F: drivers/tty/serial/atmel_serial.c
|
||||
|
||||
ATMEL SAMA5D2 ADC DRIVER
|
||||
M: Ludovic Desroches <ludovic.desroches@atmel.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iio/adc/at91-sama5d2_adc.c
|
||||
|
||||
ATMEL Audio ALSA driver
|
||||
M: Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ config MMA8452
|
|||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the following Freescale 3-axis
|
||||
accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
|
||||
accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mma8452.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* mma8452.c - Support for following Freescale 3-axis accelerometers:
|
||||
*
|
||||
* MMA8451Q (14 bit)
|
||||
* MMA8452Q (12 bit)
|
||||
* MMA8453Q (10 bit)
|
||||
* MMA8652FC (12 bit)
|
||||
|
|
@ -15,7 +16,7 @@
|
|||
*
|
||||
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
|
||||
*
|
||||
* TODO: orientation / freefall events, autosleep
|
||||
* TODO: orientation events, autosleep
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
@ -85,8 +86,9 @@
|
|||
#define MMA8452_INT_FF_MT BIT(2)
|
||||
#define MMA8452_INT_TRANS BIT(5)
|
||||
|
||||
#define MMA8452_DEVICE_ID 0x2a
|
||||
#define MMA8453_DEVICE_ID 0x3a
|
||||
#define MMA8451_DEVICE_ID 0x1a
|
||||
#define MMA8452_DEVICE_ID 0x2a
|
||||
#define MMA8453_DEVICE_ID 0x3a
|
||||
#define MMA8652_DEVICE_ID 0x4a
|
||||
#define MMA8653_DEVICE_ID 0x5a
|
||||
|
||||
|
|
@ -416,6 +418,51 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* returns >0 if in freefall mode, 0 if not or <0 if an error occured */
|
||||
static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
|
||||
{
|
||||
int val;
|
||||
const struct mma_chip_info *chip = data->chip_info;
|
||||
|
||||
val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
return !(val & MMA8452_FF_MT_CFG_OAE);
|
||||
}
|
||||
|
||||
static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state)
|
||||
{
|
||||
int val;
|
||||
const struct mma_chip_info *chip = data->chip_info;
|
||||
|
||||
if ((state && mma8452_freefall_mode_enabled(data)) ||
|
||||
(!state && !(mma8452_freefall_mode_enabled(data))))
|
||||
return 0;
|
||||
|
||||
val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (state) {
|
||||
val |= BIT(idx_x + chip->ev_cfg_chan_shift);
|
||||
val |= BIT(idx_y + chip->ev_cfg_chan_shift);
|
||||
val |= BIT(idx_z + chip->ev_cfg_chan_shift);
|
||||
val &= ~MMA8452_FF_MT_CFG_OAE;
|
||||
} else {
|
||||
val &= ~BIT(idx_x + chip->ev_cfg_chan_shift);
|
||||
val &= ~BIT(idx_y + chip->ev_cfg_chan_shift);
|
||||
val &= ~BIT(idx_z + chip->ev_cfg_chan_shift);
|
||||
val |= MMA8452_FF_MT_CFG_OAE;
|
||||
}
|
||||
|
||||
val = mma8452_change_config(data, chip->ev_cfg, val);
|
||||
if (val)
|
||||
return val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
|
||||
int val, int val2)
|
||||
{
|
||||
|
|
@ -609,12 +656,22 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
|
|||
const struct mma_chip_info *chip = data->chip_info;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
data->chip_info->ev_cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return mma8452_freefall_mode_enabled(data);
|
||||
case IIO_EV_DIR_RISING:
|
||||
if (mma8452_freefall_mode_enabled(data))
|
||||
return 0;
|
||||
|
||||
return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
data->chip_info->ev_cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mma8452_write_event_config(struct iio_dev *indio_dev,
|
||||
|
|
@ -627,19 +684,35 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
|
|||
const struct mma_chip_info *chip = data->chip_info;
|
||||
int val;
|
||||
|
||||
val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return mma8452_set_freefall_mode(data, state);
|
||||
case IIO_EV_DIR_RISING:
|
||||
val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (state)
|
||||
val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
|
||||
else
|
||||
val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
|
||||
if (state) {
|
||||
if (mma8452_freefall_mode_enabled(data)) {
|
||||
val &= ~BIT(idx_x + chip->ev_cfg_chan_shift);
|
||||
val &= ~BIT(idx_y + chip->ev_cfg_chan_shift);
|
||||
val &= ~BIT(idx_z + chip->ev_cfg_chan_shift);
|
||||
val |= MMA8452_FF_MT_CFG_OAE;
|
||||
}
|
||||
val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift);
|
||||
} else {
|
||||
if (mma8452_freefall_mode_enabled(data))
|
||||
return 0;
|
||||
|
||||
val |= chip->ev_cfg_ele;
|
||||
val |= MMA8452_FF_MT_CFG_OAE;
|
||||
val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift);
|
||||
}
|
||||
|
||||
return mma8452_change_config(data, chip->ev_cfg, val);
|
||||
val |= chip->ev_cfg_ele;
|
||||
|
||||
return mma8452_change_config(data, chip->ev_cfg, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
|
||||
|
|
@ -652,6 +725,16 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
|
|||
if (src < 0)
|
||||
return;
|
||||
|
||||
if (mma8452_freefall_mode_enabled(data)) {
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
|
||||
IIO_MOD_X_AND_Y_AND_Z,
|
||||
IIO_EV_TYPE_MAG,
|
||||
IIO_EV_DIR_FALLING),
|
||||
ts);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src & data->chip_info->ev_src_xe)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
|
||||
|
|
@ -745,6 +828,27 @@ static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_event_spec mma8452_freefall_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_MAG,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_PERIOD) |
|
||||
BIT(IIO_EV_INFO_HIGH_PASS_FILTER_3DB)
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec mma8652_freefall_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_MAG,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_PERIOD)
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec mma8452_transient_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_MAG,
|
||||
|
|
@ -781,6 +885,24 @@ static struct attribute_group mma8452_event_attribute_group = {
|
|||
.attrs = mma8452_event_attributes,
|
||||
};
|
||||
|
||||
#define MMA8452_FREEFALL_CHANNEL(modifier) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = modifier, \
|
||||
.scan_index = -1, \
|
||||
.event_spec = mma8452_freefall_event, \
|
||||
.num_event_specs = ARRAY_SIZE(mma8452_freefall_event), \
|
||||
}
|
||||
|
||||
#define MMA8652_FREEFALL_CHANNEL(modifier) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
.channel2 = modifier, \
|
||||
.scan_index = -1, \
|
||||
.event_spec = mma8652_freefall_event, \
|
||||
.num_event_specs = ARRAY_SIZE(mma8652_freefall_event), \
|
||||
}
|
||||
|
||||
#define MMA8452_CHANNEL(axis, idx, bits) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.modified = 1, \
|
||||
|
|
@ -822,11 +944,20 @@ static struct attribute_group mma8452_event_attribute_group = {
|
|||
.num_event_specs = ARRAY_SIZE(mma8452_motion_event), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mma8451_channels[] = {
|
||||
MMA8452_CHANNEL(X, idx_x, 14),
|
||||
MMA8452_CHANNEL(Y, idx_y, 14),
|
||||
MMA8452_CHANNEL(Z, idx_z, 14),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
|
||||
MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mma8452_channels[] = {
|
||||
MMA8452_CHANNEL(X, idx_x, 12),
|
||||
MMA8452_CHANNEL(Y, idx_y, 12),
|
||||
MMA8452_CHANNEL(Z, idx_z, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
|
||||
MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mma8453_channels[] = {
|
||||
|
|
@ -834,6 +965,7 @@ static const struct iio_chan_spec mma8453_channels[] = {
|
|||
MMA8452_CHANNEL(Y, idx_y, 10),
|
||||
MMA8452_CHANNEL(Z, idx_z, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
|
||||
MMA8452_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mma8652_channels[] = {
|
||||
|
|
@ -841,6 +973,7 @@ static const struct iio_chan_spec mma8652_channels[] = {
|
|||
MMA8652_CHANNEL(Y, idx_y, 12),
|
||||
MMA8652_CHANNEL(Z, idx_z, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
|
||||
MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mma8653_channels[] = {
|
||||
|
|
@ -848,9 +981,11 @@ static const struct iio_chan_spec mma8653_channels[] = {
|
|||
MMA8652_CHANNEL(Y, idx_y, 10),
|
||||
MMA8652_CHANNEL(Z, idx_z, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
|
||||
MMA8652_FREEFALL_CHANNEL(IIO_MOD_X_AND_Y_AND_Z),
|
||||
};
|
||||
|
||||
enum {
|
||||
mma8451,
|
||||
mma8452,
|
||||
mma8453,
|
||||
mma8652,
|
||||
|
|
@ -858,17 +993,34 @@ enum {
|
|||
};
|
||||
|
||||
static const struct mma_chip_info mma_chip_info_table[] = {
|
||||
[mma8451] = {
|
||||
.chip_id = MMA8451_DEVICE_ID,
|
||||
.channels = mma8451_channels,
|
||||
.num_channels = ARRAY_SIZE(mma8451_channels),
|
||||
/*
|
||||
* Hardware has fullscale of -2G, -4G, -8G corresponding to
|
||||
* raw value -8192 for 14 bit, -2048 for 12 bit or -512 for 10
|
||||
* bit.
|
||||
* The userspace interface uses m/s^2 and we declare micro units
|
||||
* So scale factor for 12 bit here is given by:
|
||||
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
|
||||
*/
|
||||
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
|
||||
.ev_cfg = MMA8452_TRANSIENT_CFG,
|
||||
.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
|
||||
.ev_cfg_chan_shift = 1,
|
||||
.ev_src = MMA8452_TRANSIENT_SRC,
|
||||
.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
|
||||
.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
|
||||
.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
|
||||
.ev_ths = MMA8452_TRANSIENT_THS,
|
||||
.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
|
||||
.ev_count = MMA8452_TRANSIENT_COUNT,
|
||||
},
|
||||
[mma8452] = {
|
||||
.chip_id = MMA8452_DEVICE_ID,
|
||||
.channels = mma8452_channels,
|
||||
.num_channels = ARRAY_SIZE(mma8452_channels),
|
||||
/*
|
||||
* Hardware has fullscale of -2G, -4G, -8G corresponding to
|
||||
* raw value -2048 for 12 bit or -512 for 10 bit.
|
||||
* The userspace interface uses m/s^2 and we declare micro units
|
||||
* So scale factor for 12 bit here is given by:
|
||||
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
|
||||
*/
|
||||
.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
|
||||
.ev_cfg = MMA8452_TRANSIENT_CFG,
|
||||
.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
|
||||
|
|
@ -1049,6 +1201,7 @@ static int mma8452_reset(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct of_device_id mma8452_dt_ids[] = {
|
||||
{ .compatible = "fsl,mma8451", .data = &mma_chip_info_table[mma8451] },
|
||||
{ .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] },
|
||||
{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
|
||||
{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
|
||||
|
|
@ -1085,6 +1238,7 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
|
||||
switch (ret) {
|
||||
case MMA8451_DEVICE_ID:
|
||||
case MMA8452_DEVICE_ID:
|
||||
case MMA8453_DEVICE_ID:
|
||||
case MMA8652_DEVICE_ID:
|
||||
|
|
@ -1190,6 +1344,10 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
ret = mma8452_set_freefall_mode(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
buffer_cleanup:
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@
|
|||
#define ST_ACCEL_1_DRDY_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_1_DRDY_IRQ_INT1_MASK 0x10
|
||||
#define ST_ACCEL_1_DRDY_IRQ_INT2_MASK 0x08
|
||||
#define ST_ACCEL_1_IHL_IRQ_ADDR 0x25
|
||||
#define ST_ACCEL_1_IHL_IRQ_MASK 0x02
|
||||
#define ST_ACCEL_1_MULTIREAD_BIT true
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 2 */
|
||||
|
|
@ -92,6 +94,8 @@
|
|||
#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_2_DRDY_IRQ_INT1_MASK 0x02
|
||||
#define ST_ACCEL_2_DRDY_IRQ_INT2_MASK 0x10
|
||||
#define ST_ACCEL_2_IHL_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_2_IHL_IRQ_MASK 0x80
|
||||
#define ST_ACCEL_2_MULTIREAD_BIT true
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 3 */
|
||||
|
|
@ -125,6 +129,8 @@
|
|||
#define ST_ACCEL_3_DRDY_IRQ_ADDR 0x23
|
||||
#define ST_ACCEL_3_DRDY_IRQ_INT1_MASK 0x80
|
||||
#define ST_ACCEL_3_DRDY_IRQ_INT2_MASK 0x00
|
||||
#define ST_ACCEL_3_IHL_IRQ_ADDR 0x23
|
||||
#define ST_ACCEL_3_IHL_IRQ_MASK 0x40
|
||||
#define ST_ACCEL_3_IG1_EN_ADDR 0x23
|
||||
#define ST_ACCEL_3_IG1_EN_MASK 0x08
|
||||
#define ST_ACCEL_3_MULTIREAD_BIT false
|
||||
|
|
@ -169,6 +175,8 @@
|
|||
#define ST_ACCEL_5_DRDY_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_5_DRDY_IRQ_INT1_MASK 0x04
|
||||
#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK 0x20
|
||||
#define ST_ACCEL_5_IHL_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_5_IHL_IRQ_MASK 0x80
|
||||
#define ST_ACCEL_5_IG1_EN_ADDR 0x21
|
||||
#define ST_ACCEL_5_IG1_EN_MASK 0x08
|
||||
#define ST_ACCEL_5_MULTIREAD_BIT false
|
||||
|
|
@ -292,6 +300,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.addr = ST_ACCEL_1_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_1_DRDY_IRQ_INT1_MASK,
|
||||
.mask_int2 = ST_ACCEL_1_DRDY_IRQ_INT2_MASK,
|
||||
.addr_ihl = ST_ACCEL_1_IHL_IRQ_ADDR,
|
||||
.mask_ihl = ST_ACCEL_1_IHL_IRQ_MASK,
|
||||
},
|
||||
.multi_read_bit = ST_ACCEL_1_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
|
|
@ -355,6 +365,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_2_DRDY_IRQ_INT1_MASK,
|
||||
.mask_int2 = ST_ACCEL_2_DRDY_IRQ_INT2_MASK,
|
||||
.addr_ihl = ST_ACCEL_2_IHL_IRQ_ADDR,
|
||||
.mask_ihl = ST_ACCEL_2_IHL_IRQ_MASK,
|
||||
},
|
||||
.multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
|
|
@ -430,6 +442,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.addr = ST_ACCEL_3_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_3_DRDY_IRQ_INT1_MASK,
|
||||
.mask_int2 = ST_ACCEL_3_DRDY_IRQ_INT2_MASK,
|
||||
.addr_ihl = ST_ACCEL_3_IHL_IRQ_ADDR,
|
||||
.mask_ihl = ST_ACCEL_3_IHL_IRQ_MASK,
|
||||
.ig1 = {
|
||||
.en_addr = ST_ACCEL_3_IG1_EN_ADDR,
|
||||
.en_mask = ST_ACCEL_3_IG1_EN_MASK,
|
||||
|
|
@ -537,6 +551,8 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.addr = ST_ACCEL_5_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_5_DRDY_IRQ_INT1_MASK,
|
||||
.mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
|
||||
.addr_ihl = ST_ACCEL_5_IHL_IRQ_ADDR,
|
||||
.mask_ihl = ST_ACCEL_5_IHL_IRQ_MASK,
|
||||
},
|
||||
.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
|
||||
.bootime = 2, /* guess */
|
||||
|
|
|
|||
|
|
@ -131,6 +131,16 @@ config AT91_ADC
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called at91_adc.
|
||||
|
||||
config AT91_SAMA5D2_ADC
|
||||
tristate "Atmel AT91 SAMA5D2 ADC"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for Atmel SAMA5D2 ADC which is
|
||||
available on SAMA5D2 SoC family.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called at91-sama5d2_adc.
|
||||
|
||||
config AXP288_ADC
|
||||
tristate "X-Powers AXP288 ADC driver"
|
||||
depends on MFD_AXP20X
|
||||
|
|
@ -265,11 +275,11 @@ config MCP320X
|
|||
called mcp320x.
|
||||
|
||||
config MCP3422
|
||||
tristate "Microchip Technology MCP3422/3/4/6/7/8 driver"
|
||||
tristate "Microchip Technology MCP3421/2/3/4/5/6/7/8 driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's
|
||||
MCP3422, MCP3423, MCP3424, MCP3426, MCP3427 or MCP3428
|
||||
Say yes here to build support for Microchip Technology's MCP3421
|
||||
MCP3422, MCP3423, MCP3424, MCP3425, MCP3426, MCP3427 or MCP3428
|
||||
analog to digital converters.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
|
|||
obj-$(CONFIG_AD7887) += ad7887.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
|
||||
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
|
||||
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
|
||||
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
|
||||
|
|
|
|||
508
drivers/iio/adc/at91-sama5d2_adc.c
Normal file
508
drivers/iio/adc/at91-sama5d2_adc.c
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* Atmel ADC driver for SAMA5D2 devices and compatible.
|
||||
*
|
||||
* Copyright (C) 2015 Atmel,
|
||||
* 2015 Ludovic Desroches <ludovic.desroches@atmel.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* Control Register */
|
||||
#define AT91_SAMA5D2_CR 0x00
|
||||
/* Software Reset */
|
||||
#define AT91_SAMA5D2_CR_SWRST BIT(0)
|
||||
/* Start Conversion */
|
||||
#define AT91_SAMA5D2_CR_START BIT(1)
|
||||
/* Touchscreen Calibration */
|
||||
#define AT91_SAMA5D2_CR_TSCALIB BIT(2)
|
||||
/* Comparison Restart */
|
||||
#define AT91_SAMA5D2_CR_CMPRST BIT(4)
|
||||
|
||||
/* Mode Register */
|
||||
#define AT91_SAMA5D2_MR 0x04
|
||||
/* Trigger Selection */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL(v) ((v) << 1)
|
||||
/* ADTRG */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG0 0
|
||||
/* TIOA0 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG1 1
|
||||
/* TIOA1 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG2 2
|
||||
/* TIOA2 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG3 3
|
||||
/* PWM event line 0 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG4 4
|
||||
/* PWM event line 1 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG5 5
|
||||
/* TIOA3 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG6 6
|
||||
/* RTCOUT0 */
|
||||
#define AT91_SAMA5D2_MR_TRGSEL_TRIG7 7
|
||||
/* Sleep Mode */
|
||||
#define AT91_SAMA5D2_MR_SLEEP BIT(5)
|
||||
/* Fast Wake Up */
|
||||
#define AT91_SAMA5D2_MR_FWUP BIT(6)
|
||||
/* Prescaler Rate Selection */
|
||||
#define AT91_SAMA5D2_MR_PRESCAL(v) ((v) << AT91_SAMA5D2_MR_PRESCAL_OFFSET)
|
||||
#define AT91_SAMA5D2_MR_PRESCAL_OFFSET 8
|
||||
#define AT91_SAMA5D2_MR_PRESCAL_MAX 0xff
|
||||
/* Startup Time */
|
||||
#define AT91_SAMA5D2_MR_STARTUP(v) ((v) << 16)
|
||||
/* Analog Change */
|
||||
#define AT91_SAMA5D2_MR_ANACH BIT(23)
|
||||
/* Tracking Time */
|
||||
#define AT91_SAMA5D2_MR_TRACKTIM(v) ((v) << 24)
|
||||
#define AT91_SAMA5D2_MR_TRACKTIM_MAX 0xff
|
||||
/* Transfer Time */
|
||||
#define AT91_SAMA5D2_MR_TRANSFER(v) ((v) << 28)
|
||||
#define AT91_SAMA5D2_MR_TRANSFER_MAX 0x3
|
||||
/* Use Sequence Enable */
|
||||
#define AT91_SAMA5D2_MR_USEQ BIT(31)
|
||||
|
||||
/* Channel Sequence Register 1 */
|
||||
#define AT91_SAMA5D2_SEQR1 0x08
|
||||
/* Channel Sequence Register 2 */
|
||||
#define AT91_SAMA5D2_SEQR2 0x0c
|
||||
/* Channel Enable Register */
|
||||
#define AT91_SAMA5D2_CHER 0x10
|
||||
/* Channel Disable Register */
|
||||
#define AT91_SAMA5D2_CHDR 0x14
|
||||
/* Channel Status Register */
|
||||
#define AT91_SAMA5D2_CHSR 0x18
|
||||
/* Last Converted Data Register */
|
||||
#define AT91_SAMA5D2_LCDR 0x20
|
||||
/* Interrupt Enable Register */
|
||||
#define AT91_SAMA5D2_IER 0x24
|
||||
/* Interrupt Disable Register */
|
||||
#define AT91_SAMA5D2_IDR 0x28
|
||||
/* Interrupt Mask Register */
|
||||
#define AT91_SAMA5D2_IMR 0x2c
|
||||
/* Interrupt Status Register */
|
||||
#define AT91_SAMA5D2_ISR 0x30
|
||||
/* Last Channel Trigger Mode Register */
|
||||
#define AT91_SAMA5D2_LCTMR 0x34
|
||||
/* Last Channel Compare Window Register */
|
||||
#define AT91_SAMA5D2_LCCWR 0x38
|
||||
/* Overrun Status Register */
|
||||
#define AT91_SAMA5D2_OVER 0x3c
|
||||
/* Extended Mode Register */
|
||||
#define AT91_SAMA5D2_EMR 0x40
|
||||
/* Compare Window Register */
|
||||
#define AT91_SAMA5D2_CWR 0x44
|
||||
/* Channel Gain Register */
|
||||
#define AT91_SAMA5D2_CGR 0x48
|
||||
/* Channel Offset Register */
|
||||
#define AT91_SAMA5D2_COR 0x4c
|
||||
/* Channel Data Register 0 */
|
||||
#define AT91_SAMA5D2_CDR0 0x50
|
||||
/* Analog Control Register */
|
||||
#define AT91_SAMA5D2_ACR 0x94
|
||||
/* Touchscreen Mode Register */
|
||||
#define AT91_SAMA5D2_TSMR 0xb0
|
||||
/* Touchscreen X Position Register */
|
||||
#define AT91_SAMA5D2_XPOSR 0xb4
|
||||
/* Touchscreen Y Position Register */
|
||||
#define AT91_SAMA5D2_YPOSR 0xb8
|
||||
/* Touchscreen Pressure Register */
|
||||
#define AT91_SAMA5D2_PRESSR 0xbc
|
||||
/* Trigger Register */
|
||||
#define AT91_SAMA5D2_TRGR 0xc0
|
||||
/* Correction Select Register */
|
||||
#define AT91_SAMA5D2_COSR 0xd0
|
||||
/* Correction Value Register */
|
||||
#define AT91_SAMA5D2_CVR 0xd4
|
||||
/* Channel Error Correction Register */
|
||||
#define AT91_SAMA5D2_CECR 0xd8
|
||||
/* Write Protection Mode Register */
|
||||
#define AT91_SAMA5D2_WPMR 0xe4
|
||||
/* Write Protection Status Register */
|
||||
#define AT91_SAMA5D2_WPSR 0xe8
|
||||
/* Version Register */
|
||||
#define AT91_SAMA5D2_VERSION 0xfc
|
||||
|
||||
#define AT91_AT91_SAMA5D2_CHAN(num, addr) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = num, \
|
||||
.address = addr, \
|
||||
.scan_type = { \
|
||||
.sign = 'u', \
|
||||
.realbits = 12, \
|
||||
}, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
|
||||
.datasheet_name = "CH"#num, \
|
||||
.indexed = 1, \
|
||||
}
|
||||
|
||||
#define at91_adc_readl(st, reg) readl_relaxed(st->base + reg)
|
||||
#define at91_adc_writel(st, reg, val) writel_relaxed(val, st->base + reg)
|
||||
|
||||
struct at91_adc_soc_info {
|
||||
unsigned startup_time;
|
||||
unsigned min_sample_rate;
|
||||
unsigned max_sample_rate;
|
||||
};
|
||||
|
||||
struct at91_adc_state {
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
struct clk *per_clk;
|
||||
struct regulator *reg;
|
||||
struct regulator *vref;
|
||||
int vref_uv;
|
||||
const struct iio_chan_spec *chan;
|
||||
bool conversion_done;
|
||||
u32 conversion_value;
|
||||
struct at91_adc_soc_info soc_info;
|
||||
wait_queue_head_t wq_data_available;
|
||||
/*
|
||||
* lock to prevent concurrent 'single conversion' requests through
|
||||
* sysfs.
|
||||
*/
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec at91_adc_channels[] = {
|
||||
AT91_AT91_SAMA5D2_CHAN(0, 0x50),
|
||||
AT91_AT91_SAMA5D2_CHAN(1, 0x54),
|
||||
AT91_AT91_SAMA5D2_CHAN(2, 0x58),
|
||||
AT91_AT91_SAMA5D2_CHAN(3, 0x5c),
|
||||
AT91_AT91_SAMA5D2_CHAN(4, 0x60),
|
||||
AT91_AT91_SAMA5D2_CHAN(5, 0x64),
|
||||
AT91_AT91_SAMA5D2_CHAN(6, 0x68),
|
||||
AT91_AT91_SAMA5D2_CHAN(7, 0x6c),
|
||||
AT91_AT91_SAMA5D2_CHAN(8, 0x70),
|
||||
AT91_AT91_SAMA5D2_CHAN(9, 0x74),
|
||||
AT91_AT91_SAMA5D2_CHAN(10, 0x78),
|
||||
AT91_AT91_SAMA5D2_CHAN(11, 0x7c),
|
||||
};
|
||||
|
||||
static unsigned at91_adc_startup_time(unsigned startup_time_min,
|
||||
unsigned adc_clk_khz)
|
||||
{
|
||||
const unsigned startup_lookup[] = {
|
||||
0, 8, 16, 24,
|
||||
64, 80, 96, 112,
|
||||
512, 576, 640, 704,
|
||||
768, 832, 896, 960
|
||||
};
|
||||
unsigned ticks_min, i;
|
||||
|
||||
/*
|
||||
* Since the adc frequency is checked before, there is no reason
|
||||
* to not meet the startup time constraint.
|
||||
*/
|
||||
|
||||
ticks_min = startup_time_min * adc_clk_khz / 1000;
|
||||
for (i = 0; i < ARRAY_SIZE(startup_lookup); i++)
|
||||
if (startup_lookup[i] > ticks_min)
|
||||
break;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(st);
|
||||
unsigned f_per, prescal, startup;
|
||||
|
||||
f_per = clk_get_rate(st->per_clk);
|
||||
prescal = (f_per / (2 * freq)) - 1;
|
||||
|
||||
startup = at91_adc_startup_time(st->soc_info.startup_time,
|
||||
freq / 1000);
|
||||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_MR,
|
||||
AT91_SAMA5D2_MR_TRANSFER(2)
|
||||
| AT91_SAMA5D2_MR_STARTUP(startup)
|
||||
| AT91_SAMA5D2_MR_PRESCAL(prescal));
|
||||
|
||||
dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
|
||||
freq, startup, prescal);
|
||||
}
|
||||
|
||||
static unsigned at91_adc_get_sample_freq(struct at91_adc_state *st)
|
||||
{
|
||||
unsigned f_adc, f_per = clk_get_rate(st->per_clk);
|
||||
unsigned mr, prescal;
|
||||
|
||||
mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
|
||||
prescal = (mr >> AT91_SAMA5D2_MR_PRESCAL_OFFSET)
|
||||
& AT91_SAMA5D2_MR_PRESCAL_MAX;
|
||||
f_adc = f_per / (2 * (prescal + 1));
|
||||
|
||||
return f_adc;
|
||||
}
|
||||
|
||||
static irqreturn_t at91_adc_interrupt(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio = private;
|
||||
struct at91_adc_state *st = iio_priv(indio);
|
||||
u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
|
||||
u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
|
||||
|
||||
if (status & imr) {
|
||||
st->conversion_value = at91_adc_readl(st, st->chan->address);
|
||||
st->conversion_done = true;
|
||||
wake_up_interruptible(&st->wq_data_available);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int at91_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct at91_adc_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
st->chan = chan;
|
||||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
|
||||
at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
|
||||
|
||||
ret = wait_event_interruptible_timeout(st->wq_data_available,
|
||||
st->conversion_done,
|
||||
msecs_to_jiffies(1000));
|
||||
if (ret == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
if (ret > 0) {
|
||||
*val = st->conversion_value;
|
||||
ret = IIO_VAL_INT;
|
||||
st->conversion_done = false;
|
||||
}
|
||||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->vref_uv / 1000;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = at91_adc_get_sample_freq(st);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int at91_adc_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct at91_adc_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (mask != IIO_CHAN_INFO_SAMP_FREQ)
|
||||
return -EINVAL;
|
||||
|
||||
if (val < st->soc_info.min_sample_rate ||
|
||||
val > st->soc_info.max_sample_rate)
|
||||
return -EINVAL;
|
||||
|
||||
at91_adc_setup_samp_freq(st, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info at91_adc_info = {
|
||||
.read_raw = &at91_adc_read_raw,
|
||||
.write_raw = &at91_adc_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int at91_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct at91_adc_state *st;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &at91_adc_info;
|
||||
indio_dev->channels = at91_adc_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(at91_adc_channels);
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"atmel,min-sample-rate-hz",
|
||||
&st->soc_info.min_sample_rate);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"invalid or missing value for atmel,min-sample-rate-hz\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"atmel,max-sample-rate-hz",
|
||||
&st->soc_info.max_sample_rate);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"invalid or missing value for atmel,max-sample-rate-hz\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "atmel,startup-time-ms",
|
||||
&st->soc_info.startup_time);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"invalid or missing value for atmel,startup-time-ms\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&st->wq_data_available);
|
||||
mutex_init(&st->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
st->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(st->base))
|
||||
return PTR_ERR(st->base);
|
||||
|
||||
st->irq = platform_get_irq(pdev, 0);
|
||||
if (st->irq <= 0) {
|
||||
if (!st->irq)
|
||||
st->irq = -ENXIO;
|
||||
|
||||
return st->irq;
|
||||
}
|
||||
|
||||
st->per_clk = devm_clk_get(&pdev->dev, "adc_clk");
|
||||
if (IS_ERR(st->per_clk))
|
||||
return PTR_ERR(st->per_clk);
|
||||
|
||||
st->reg = devm_regulator_get(&pdev->dev, "vddana");
|
||||
if (IS_ERR(st->reg))
|
||||
return PTR_ERR(st->reg);
|
||||
|
||||
st->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(st->vref))
|
||||
return PTR_ERR(st->vref);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, st->irq, at91_adc_interrupt, 0,
|
||||
pdev->dev.driver->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(st->vref);
|
||||
if (ret)
|
||||
goto reg_disable;
|
||||
|
||||
st->vref_uv = regulator_get_voltage(st->vref);
|
||||
if (st->vref_uv <= 0) {
|
||||
ret = -EINVAL;
|
||||
goto vref_disable;
|
||||
}
|
||||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
|
||||
at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
|
||||
|
||||
at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
|
||||
|
||||
ret = clk_prepare_enable(st->per_clk);
|
||||
if (ret)
|
||||
goto vref_disable;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto per_clk_disable_unprepare;
|
||||
|
||||
dev_info(&pdev->dev, "version: %x\n",
|
||||
readl_relaxed(st->base + AT91_SAMA5D2_VERSION));
|
||||
|
||||
return 0;
|
||||
|
||||
per_clk_disable_unprepare:
|
||||
clk_disable_unprepare(st->per_clk);
|
||||
vref_disable:
|
||||
regulator_disable(st->vref);
|
||||
reg_disable:
|
||||
regulator_disable(st->reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int at91_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct at91_adc_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
clk_disable_unprepare(st->per_clk);
|
||||
|
||||
regulator_disable(st->vref);
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id at91_adc_dt_match[] = {
|
||||
{
|
||||
.compatible = "atmel,sama5d2-adc",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at91_adc_dt_match);
|
||||
|
||||
static struct platform_driver at91_adc_driver = {
|
||||
.probe = at91_adc_probe,
|
||||
.remove = at91_adc_remove,
|
||||
.driver = {
|
||||
.name = "at91-sama5d2_adc",
|
||||
.of_match_table = at91_adc_dt_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(at91_adc_driver)
|
||||
|
||||
MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@atmel.com>");
|
||||
MODULE_DESCRIPTION("Atmel AT91 SAMA5D2 ADC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -46,7 +46,7 @@ struct axp288_adc_info {
|
|||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec const axp288_adc_channels[] = {
|
||||
static const struct iio_chan_spec axp288_adc_channels[] = {
|
||||
{
|
||||
.indexed = 1,
|
||||
.type = IIO_TEMP,
|
||||
|
|
|
|||
|
|
@ -187,26 +187,27 @@ out:
|
|||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
}
|
||||
|
||||
#define MCP320X_VOLTAGE_CHANNEL_DIFF(num) \
|
||||
#define MCP320X_VOLTAGE_CHANNEL_DIFF(chan1, chan2) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (num * 2), \
|
||||
.channel2 = (num * 2 + 1), \
|
||||
.address = (num * 2), \
|
||||
.channel = (chan1), \
|
||||
.channel2 = (chan2), \
|
||||
.address = (chan1), \
|
||||
.differential = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mcp3201_channels[] = {
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0, 1),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mcp3202_channels[] = {
|
||||
MCP320X_VOLTAGE_CHANNEL(0),
|
||||
MCP320X_VOLTAGE_CHANNEL(1),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0, 1),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(1, 0),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mcp3204_channels[] = {
|
||||
|
|
@ -214,8 +215,10 @@ static const struct iio_chan_spec mcp3204_channels[] = {
|
|||
MCP320X_VOLTAGE_CHANNEL(1),
|
||||
MCP320X_VOLTAGE_CHANNEL(2),
|
||||
MCP320X_VOLTAGE_CHANNEL(3),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(1),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0, 1),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(1, 0),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(2, 3),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(3, 2),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mcp3208_channels[] = {
|
||||
|
|
@ -227,10 +230,14 @@ static const struct iio_chan_spec mcp3208_channels[] = {
|
|||
MCP320X_VOLTAGE_CHANNEL(5),
|
||||
MCP320X_VOLTAGE_CHANNEL(6),
|
||||
MCP320X_VOLTAGE_CHANNEL(7),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(1),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(2),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(3),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(0, 1),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(1, 0),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(2, 3),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(3, 2),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(4, 5),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(5, 4),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(6, 7),
|
||||
MCP320X_VOLTAGE_CHANNEL_DIFF(7, 6),
|
||||
};
|
||||
|
||||
static const struct iio_info mcp320x_info = {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* mcp3422.c - driver for the Microchip mcp3422/3/4/6/7/8 chip family
|
||||
* mcp3422.c - driver for the Microchip mcp3421/2/3/4/5/6/7/8 chip family
|
||||
*
|
||||
* Copyright (C) 2013, Angelo Compagnucci
|
||||
* Author: Angelo Compagnucci <angelo.compagnucci@gmail.com>
|
||||
*
|
||||
* Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/22088b.pdf
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/22226a.pdf
|
||||
* http://ww1.microchip.com/downloads/en/DeviceDoc/22072b.pdf
|
||||
*
|
||||
* This driver exports the value of analog input voltage to sysfs, the
|
||||
* voltage unit is nV.
|
||||
|
|
@ -357,6 +358,7 @@ static int mcp3422_probe(struct i2c_client *client,
|
|||
|
||||
switch (adc->id) {
|
||||
case 1:
|
||||
case 5:
|
||||
indio_dev->channels = mcp3421_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels);
|
||||
break;
|
||||
|
|
@ -395,6 +397,7 @@ static const struct i2c_device_id mcp3422_id[] = {
|
|||
{ "mcp3422", 2 },
|
||||
{ "mcp3423", 3 },
|
||||
{ "mcp3424", 4 },
|
||||
{ "mcp3425", 5 },
|
||||
{ "mcp3426", 6 },
|
||||
{ "mcp3427", 7 },
|
||||
{ "mcp3428", 8 },
|
||||
|
|
@ -421,5 +424,5 @@ static struct i2c_driver mcp3422_driver = {
|
|||
module_i2c_driver(mcp3422_driver);
|
||||
|
||||
MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>");
|
||||
MODULE_DESCRIPTION("Microchip mcp3422/3/4/6/7/8 driver");
|
||||
MODULE_DESCRIPTION("Microchip mcp3421/2/3/4/5/6/7/8 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
|||
|
|
@ -4,6 +4,19 @@
|
|||
|
||||
menu "Chemical Sensors"
|
||||
|
||||
config ATLAS_PH_SENSOR
|
||||
tristate "Atlas Scientific OEM pH-SM sensor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here to build I2C interface support for the Atlas
|
||||
Scientific OEM pH-SM sensor.
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called atlas-ph-sensor.
|
||||
|
||||
config IAQCORE
|
||||
tristate "AMS iAQ-Core VOC sensors"
|
||||
depends on I2C
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue