Third set of IIO new device support, features and cleanups for the 4.8 cycle.
New core features - Selection of the clock source for IIO timestamps. This is done per device as it makes little sense to have events in one timebase and data timestamped on another. Biggest reason for this is that we currently use a clock source which is non monotonic which can result in 'interesting' data sets. (Includes export for get_monotonic_corse64 which Thomas Gleixner didn't mind in an earlier version.) - MAINTAINERS add the git tree to the list for IIO. New device support + a kind of indirect staging graduation. * Broadcom iproc-static-adc - new driver * mcp4531 - support for MCP454x, MCP456x, MCP464x and MCP466x potentiometers * mpu6050 - support the IC20608 6 axis motion tracking device * st-sensors - support the lis3l02dq + drop the lis3l02dq driver from staging. The general purpose driver is missing event support, but good to get rid of this driver which was rather long in the tooth. New driver features * ak8975 - Add vid regulator support and refactor handling in general. - Allow a delay after enabling regulators. - Runtime and system PM. * bmg160 - filter frequency control support. * bmp280 - SPI device support. - EOC interrupt support for the BMP085 - power management support. - supply regulator support. - reset gpio support - dt bindings for reset gpio and regulators. - of table to support device tree registration * max1363 - Device tree bindings. * mcp4531 - Device tree bindings. * st-pressure - temperature channels as part of triggered buffer (previously not due probably to alignment issues - see below). - lps22hb open drain interrupt support. - lps22hb temperature channel support Cleanups and reworkings. * numerous ADC drivers - ensure the iio_dev->dev.of_node is set to the parent dev.of_node so as to allow client bindings to find the device. * ak8975 - Fix incorrect handling of missing regulator - make sure power is down and remove. * bmp280 - read the calibration data only once as it doesn't change. * isl29125 - Use a few macros to make code a touch more readable. * mma8452 - fix a memory leak on error. - drop an unecessary bit of return value handling. * potentiometer kconfig - typo fix. * st-pressure - drop some uninformative default assignments of elements of the channel array structure (aids readability). * st-sensors - Harden interrupt handling considerably. These are actually all using level interrupts, but at least two known boards have them wired to edge only interrupt chips. Hence a slightly interesting bit of handling is needed in which we first allow for the easy option (level triggered) and secondly check the status registers before reenabling edge interrupts and fall back to a tight loop in the thread until we successfully clear the interrupt. No harm is done if we never succeed in doing so. It's an odd patch that has been through a lot of revisions to reach a consensus on how to handle what is basically broken hardware (which the previous defaults allowed to kind of work). - Fix alignment to defined storagebytes boundaries. - Ensure alignment of power of 2 byte boundaries. This has always in theory been part of the ABI of IIO, but we missed a few that snuck in that need fixing. The effect was minor as they were only followed by timestamp channels which were correctly aligned, - Add some docs to explain the gain calculations. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIuBAABCAAYBQJXfBqnERxqaWMyM0BrZXJuZWwub3JnAAoJEFSFNJnE9BaIqjwP /0OJbr8kIa1i6+iCqCRCPCixdymd6k9wvjDaKSQoDeamen+8iKOLZNhXJJjOX8hd eCRMrCJbvY96Bl2Ll51TCEBb8R1xppCwwYIYylKhF9CL6N2ndapzWY0G4XZb6pc0 e1JIa6uxynAAEsfplBskk4Ytf5PPHDOWER5WsTmxlZcTTAL9gLxIlii2Du0AmeN/ tANVzwuvK07i5HHuZfYV2h2+OWDSlm4Y5rvE7t8keWpp6wnZ0XtiIw1WjkpR1OY7 KiKGKRJMomFlp51hP9IKqc20Dweiaf3lHS7BDggvkB11VxyajQTcjvogxQ0BSPUv 7PTHHlk8txgEUMqrDWP8x0TL97iNt3hiOZ0/rI3IZdFLC8pnibewnB+uHEGCH3tv bqToPtpJHjsIiGlCGVxvt8BRgqT5Qq7JT65hYS6774uFcQiPEvPDI44BDqUxaDUf /1WFM23VB4KJpx8JnL+nC8iu6DBnVPDWDKAsjGgc+ljnz3VRcSxWz5P0yMFZRMA2 mbLiG2yiD4oD/LcI8FeZh9X50Irg09ElAWu07VRymrYMRfCYLXO07o5nZJ0bOqOB R+1MToYaHz2g6jJ+KGVC0Ul5EuULzymqH0CMbdjWnaD9AaoPuOKkNfUVBkzRK0t/ TO/wLHm/qNbk+zGZHQFU15mH1Nn9leEJ/uCdnGqkRo7i =FxNN -----END PGP SIGNATURE----- Merge tag 'iio-for-4.8c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Third set of IIO new device support, features and cleanups for the 4.8 cycle. New core features - Selection of the clock source for IIO timestamps. This is done per device as it makes little sense to have events in one timebase and data timestamped on another. Biggest reason for this is that we currently use a clock source which is non monotonic which can result in 'interesting' data sets. (Includes export for get_monotonic_corse64 which Thomas Gleixner didn't mind in an earlier version.) - MAINTAINERS add the git tree to the list for IIO. New device support + a kind of indirect staging graduation. * Broadcom iproc-static-adc - new driver * mcp4531 - support for MCP454x, MCP456x, MCP464x and MCP466x potentiometers * mpu6050 - support the IC20608 6 axis motion tracking device * st-sensors - support the lis3l02dq + drop the lis3l02dq driver from staging. The general purpose driver is missing event support, but good to get rid of this driver which was rather long in the tooth. New driver features * ak8975 - Add vid regulator support and refactor handling in general. - Allow a delay after enabling regulators. - Runtime and system PM. * bmg160 - filter frequency control support. * bmp280 - SPI device support. - EOC interrupt support for the BMP085 - power management support. - supply regulator support. - reset gpio support - dt bindings for reset gpio and regulators. - of table to support device tree registration * max1363 - Device tree bindings. * mcp4531 - Device tree bindings. * st-pressure - temperature channels as part of triggered buffer (previously not due probably to alignment issues - see below). - lps22hb open drain interrupt support. - lps22hb temperature channel support Cleanups and reworkings. * numerous ADC drivers - ensure the iio_dev->dev.of_node is set to the parent dev.of_node so as to allow client bindings to find the device. * ak8975 - Fix incorrect handling of missing regulator - make sure power is down and remove. * bmp280 - read the calibration data only once as it doesn't change. * isl29125 - Use a few macros to make code a touch more readable. * mma8452 - fix a memory leak on error. - drop an unecessary bit of return value handling. * potentiometer kconfig - typo fix. * st-pressure - drop some uninformative default assignments of elements of the channel array structure (aids readability). * st-sensors - Harden interrupt handling considerably. These are actually all using level interrupts, but at least two known boards have them wired to edge only interrupt chips. Hence a slightly interesting bit of handling is needed in which we first allow for the easy option (level triggered) and secondly check the status registers before reenabling edge interrupts and fall back to a tight loop in the thread until we successfully clear the interrupt. No harm is done if we never succeed in doing so. It's an odd patch that has been through a lot of revisions to reach a consensus on how to handle what is basically broken hardware (which the previous defaults allowed to kind of work). - Fix alignment to defined storagebytes boundaries. - Ensure alignment of power of 2 byte boundaries. This has always in theory been part of the ABI of IIO, but we missed a few that snuck in that need fixing. The effect was minor as they were only followed by timestamp channels which were correctly aligned, - Add some docs to explain the gain calculations.
This commit is contained in:
commit
6c71ee3b61
@ -32,6 +32,13 @@ Description:
|
||||
Description of the physical chip / device for device X.
|
||||
Typically a part number.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/timestamp_clock
|
||||
KernelVersion: 4.5
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
String identifying current posix clock used to timestamp
|
||||
buffered samples and events for device X.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency
|
||||
What: /sys/bus/iio/devices/triggerX/sampling_frequency
|
||||
|
@ -594,7 +594,7 @@
|
||||
|
||||
irqreturn_t sensor_iio_pollfunc(int irq, void *p)
|
||||
{
|
||||
pf->timestamp = iio_get_time_ns();
|
||||
pf->timestamp = iio_get_time_ns((struct indio_dev *)p);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,70 @@ maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
|
||||
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
|
||||
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
|
||||
mc,rv3029c2 Real Time Clock Module with I2C-Bus
|
||||
microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4531-103 Microchip 7-bit Single I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4531-503 Microchip 7-bit Single I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4531-104 Microchip 7-bit Single I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4532-502 Microchip 7-bit Single I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4532-103 Microchip 7-bit Single I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4532-503 Microchip 7-bit Single I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4532-104 Microchip 7-bit Single I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4541-502 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4541-103 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4541-503 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4541-104 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4542-502 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4542-103 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4542-503 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4542-104 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4551-502 Microchip 8-bit Single I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4551-103 Microchip 8-bit Single I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4551-503 Microchip 8-bit Single I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4551-104 Microchip 8-bit Single I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4552-502 Microchip 8-bit Single I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4552-103 Microchip 8-bit Single I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4552-503 Microchip 8-bit Single I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4552-104 Microchip 8-bit Single I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4561-502 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4561-103 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4561-503 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4561-104 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4562-502 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4562-103 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4562-503 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4562-104 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4631-502 Microchip 7-bit Dual I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4631-103 Microchip 7-bit Dual I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4631-503 Microchip 7-bit Dual I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4631-104 Microchip 7-bit Dual I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4632-502 Microchip 7-bit Dual I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4632-103 Microchip 7-bit Dual I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4632-503 Microchip 7-bit Dual I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4632-104 Microchip 7-bit Dual I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4641-502 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4641-103 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4641-503 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4641-104 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4642-502 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4642-103 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4642-503 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4642-104 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4651-502 Microchip 8-bit Dual I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4651-103 Microchip 8-bit Dual I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4651-503 Microchip 8-bit Dual I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4651-104 Microchip 8-bit Dual I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4652-502 Microchip 8-bit Dual I2C Digital Potentiometer (5k)
|
||||
microchip,mcp4652-103 Microchip 8-bit Dual I2C Digital Potentiometer (10k)
|
||||
microchip,mcp4652-503 Microchip 8-bit Dual I2C Digital Potentiometer (50k)
|
||||
microchip,mcp4652-104 Microchip 8-bit Dual I2C Digital Potentiometer (100k)
|
||||
microchip,mcp4661-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4661-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4661-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4661-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k)
|
||||
microchip,mcp4662-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (5k)
|
||||
microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k)
|
||||
microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k)
|
||||
microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k)
|
||||
national,lm63 Temperature sensor with integrated fan control
|
||||
national,lm75 I2C TEMP SENSOR
|
||||
national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor
|
||||
|
@ -0,0 +1,41 @@
|
||||
* Broadcom's IPROC Static ADC controller
|
||||
|
||||
Broadcom iProc ADC controller has 8 channels 10bit ADC.
|
||||
Allows user to convert analog input voltage values to digital.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "brcm,iproc-static-adc"
|
||||
|
||||
- adc-syscon: Handler of syscon node defining physical base address of the
|
||||
controller and length of memory mapped region.
|
||||
|
||||
- #io-channel-cells = <1>; As ADC has multiple outputs
|
||||
refer to Documentation/devicetree/bindings/iio/iio-bindings.txt for details.
|
||||
|
||||
- io-channel-ranges:
|
||||
refer to Documentation/devicetree/bindings/iio/iio-bindings.txt for details.
|
||||
|
||||
- clocks: Clock used for this block.
|
||||
|
||||
- clock-names: Clock name should be given as tsc_clk.
|
||||
|
||||
- interrupts: interrupt line number.
|
||||
|
||||
For example:
|
||||
|
||||
ts_adc_syscon: ts_adc_syscon@180a6000 {
|
||||
compatible = "brcm,iproc-ts-adc-syscon","syscon";
|
||||
reg = <0x180a6000 0xc30>;
|
||||
};
|
||||
|
||||
adc: adc@180a6000 {
|
||||
compatible = "brcm,iproc-static-adc";
|
||||
adc-syscon = <&ts_adc_syscon>;
|
||||
#io-channel-cells = <1>;
|
||||
io-channel-ranges;
|
||||
clocks = <&asiu_clks BCM_CYGNUS_ASIU_ADC_CLK>;
|
||||
clock-names = "tsc_clk";
|
||||
interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
|
||||
status = "disabled";
|
||||
};
|
63
Documentation/devicetree/bindings/iio/adc/max1363.txt
Normal file
63
Documentation/devicetree/bindings/iio/adc/max1363.txt
Normal file
@ -0,0 +1,63 @@
|
||||
* Maxim 1x3x/136x/116xx Analog to Digital Converter (ADC)
|
||||
|
||||
The node for this driver must be a child node of a I2C controller, hence
|
||||
all mandatory properties for your controller must be specified. See directory:
|
||||
|
||||
Documentation/devicetree/bindings/i2c
|
||||
|
||||
for more details.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
"maxim,max1361"
|
||||
"maxim,max1362"
|
||||
"maxim,max1363"
|
||||
"maxim,max1364"
|
||||
"maxim,max1036"
|
||||
"maxim,max1037"
|
||||
"maxim,max1038"
|
||||
"maxim,max1039"
|
||||
"maxim,max1136"
|
||||
"maxim,max1137"
|
||||
"maxim,max1138"
|
||||
"maxim,max1139"
|
||||
"maxim,max1236"
|
||||
"maxim,max1237"
|
||||
"maxim,max1238"
|
||||
"maxim,max1239"
|
||||
"maxim,max11600"
|
||||
"maxim,max11601"
|
||||
"maxim,max11602"
|
||||
"maxim,max11603"
|
||||
"maxim,max11604"
|
||||
"maxim,max11605"
|
||||
"maxim,max11606"
|
||||
"maxim,max11607"
|
||||
"maxim,max11608"
|
||||
"maxim,max11609"
|
||||
"maxim,max11610"
|
||||
"maxim,max11611"
|
||||
"maxim,max11612"
|
||||
"maxim,max11613"
|
||||
"maxim,max11614"
|
||||
"maxim,max11615"
|
||||
"maxim,max11616"
|
||||
"maxim,max11617"
|
||||
"maxim,max11644"
|
||||
"maxim,max11645"
|
||||
"maxim,max11646"
|
||||
"maxim,max11647"
|
||||
- reg: Should contain the ADC I2C address
|
||||
|
||||
Optional properties:
|
||||
- vcc-supply: phandle to the regulator that provides power to the ADC.
|
||||
- vref-supply: phandle to the regulator for ADC reference voltage.
|
||||
- interrupts: IRQ line for the ADC. If not used the driver will use
|
||||
polling.
|
||||
|
||||
Example:
|
||||
adc: max11644@36 {
|
||||
compatible = "maxim,max11644";
|
||||
reg = <0x36>;
|
||||
vref-supply = <&adc_vref>;
|
||||
};
|
@ -1,7 +1,11 @@
|
||||
BMP085/BMP18x digital pressure sensors
|
||||
BMP085/BMP18x/BMP28x digital pressure sensors
|
||||
|
||||
Required properties:
|
||||
- compatible: bosch,bmp085
|
||||
- compatible: must be one of:
|
||||
"bosch,bmp085"
|
||||
"bosch,bmp180"
|
||||
"bosch,bmp280"
|
||||
"bosch,bme280"
|
||||
|
||||
Optional properties:
|
||||
- chip-id: configurable chip id for non-default chip revisions
|
||||
@ -10,6 +14,10 @@ Optional properties:
|
||||
value range is 0-3 with rising sensitivity.
|
||||
- interrupt-parent: should be the phandle for the interrupt controller
|
||||
- interrupts: interrupt mapping for IRQ
|
||||
- reset-gpios: a GPIO line handling reset of the sensor: as the line is
|
||||
active low, it should be marked GPIO_ACTIVE_LOW (see gpio/gpio.txt)
|
||||
- vddd-supply: digital voltage regulator (see regulator/regulator.txt)
|
||||
- vdda-supply: analog voltage regulator (see regulator/regulator.txt)
|
||||
|
||||
Example:
|
||||
|
||||
@ -21,4 +29,7 @@ pressure@77 {
|
||||
default-oversampling = <2>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
|
||||
reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;
|
||||
vddd-supply = <&foo>;
|
||||
vdda-supply = <&bar>;
|
||||
};
|
||||
|
Before Width: | Height: | Size: 701 B After Width: | Height: | Size: 1.1 KiB |
@ -5789,6 +5789,7 @@ R: Hartmut Knaack <knaack.h@gmx.de>
|
||||
R: Lars-Peter Clausen <lars@metafoo.de>
|
||||
R: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
|
||||
L: linux-iio@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/
|
||||
F: drivers/iio/
|
||||
|
@ -654,7 +654,7 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct bma180_data *data = iio_priv(indio_dev);
|
||||
int64_t time_ns = iio_get_time_ns();
|
||||
s64 time_ns = iio_get_time_ns(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
@ -901,7 +901,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
|
||||
*/
|
||||
if (!irq) {
|
||||
data->old_timestamp = data->timestamp;
|
||||
data->timestamp = iio_get_time_ns();
|
||||
data->timestamp = iio_get_time_ns(indio_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1303,7 +1303,7 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
|
||||
int i;
|
||||
|
||||
data->old_timestamp = data->timestamp;
|
||||
data->timestamp = iio_get_time_ns();
|
||||
data->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
|
||||
if (data->triggers[i].enabled) {
|
||||
|
@ -1129,7 +1129,7 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
data->timestamp = iio_get_time_ns();
|
||||
data->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
if (data->dready_trigger_on)
|
||||
iio_trigger_poll(data->dready_trig);
|
||||
|
@ -97,7 +97,8 @@ static irqreturn_t mma7455_trigger_handler(int irq, void *p)
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -634,11 +634,7 @@ static int mma8452_set_freefall_mode(struct mma8452_data *data, bool state)
|
||||
val |= MMA8452_FF_MT_CFG_OAE;
|
||||
}
|
||||
|
||||
val = mma8452_change_config(data, chip->ev_cfg, val);
|
||||
if (val)
|
||||
return val;
|
||||
|
||||
return 0;
|
||||
return mma8452_change_config(data, chip->ev_cfg, val);
|
||||
}
|
||||
|
||||
static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
|
||||
@ -917,7 +913,7 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
|
||||
static void mma8452_transient_interrupt(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
s64 ts = iio_get_time_ns();
|
||||
s64 ts = iio_get_time_ns(indio_dev);
|
||||
int src;
|
||||
|
||||
src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src);
|
||||
@ -997,7 +993,7 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -1579,8 +1575,8 @@ static int mma8452_probe(struct i2c_client *client,
|
||||
goto buffer_cleanup;
|
||||
|
||||
ret = mma8452_set_freefall_mode(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -391,7 +391,7 @@ static irqreturn_t mma9551_event_handler(int irq, void *private)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1),
|
||||
IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
@ -1001,7 +1001,7 @@ static irqreturn_t mma9553_irq_handler(int irq, void *private)
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct mma9553_data *data = iio_priv(indio_dev);
|
||||
|
||||
data->timestamp = iio_get_time_ns();
|
||||
data->timestamp = iio_get_time_ns(indio_dev);
|
||||
/*
|
||||
* Since we only configure the interrupt pin when an
|
||||
* event is enabled, we are sure we have at least
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
|
||||
#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel"
|
||||
#define LIS2DH12_ACCEL_DEV_NAME "lis2dh12_accel"
|
||||
#define LIS3L02DQ_ACCEL_DEV_NAME "lis3l02dq"
|
||||
|
||||
/**
|
||||
* struct st_sensors_platform_data - default accel platform data
|
||||
|
@ -215,6 +215,22 @@
|
||||
#define ST_ACCEL_6_IHL_IRQ_MASK 0x80
|
||||
#define ST_ACCEL_6_MULTIREAD_BIT true
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 7 */
|
||||
#define ST_ACCEL_7_ODR_ADDR 0x20
|
||||
#define ST_ACCEL_7_ODR_MASK 0x30
|
||||
#define ST_ACCEL_7_ODR_AVL_280HZ_VAL 0x00
|
||||
#define ST_ACCEL_7_ODR_AVL_560HZ_VAL 0x01
|
||||
#define ST_ACCEL_7_ODR_AVL_1120HZ_VAL 0x02
|
||||
#define ST_ACCEL_7_ODR_AVL_4480HZ_VAL 0x03
|
||||
#define ST_ACCEL_7_PW_ADDR 0x20
|
||||
#define ST_ACCEL_7_PW_MASK 0xc0
|
||||
#define ST_ACCEL_7_FS_AVL_2_GAIN IIO_G_TO_M_S_2(488)
|
||||
#define ST_ACCEL_7_BDU_ADDR 0x21
|
||||
#define ST_ACCEL_7_BDU_MASK 0x40
|
||||
#define ST_ACCEL_7_DRDY_IRQ_ADDR 0x21
|
||||
#define ST_ACCEL_7_DRDY_IRQ_INT1_MASK 0x04
|
||||
#define ST_ACCEL_7_MULTIREAD_BIT false
|
||||
|
||||
static const struct iio_chan_spec st_accel_8bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
@ -662,6 +678,54 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
||||
.multi_read_bit = ST_ACCEL_6_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
{
|
||||
/* No WAI register present */
|
||||
.sensors_supported = {
|
||||
[0] = LIS3L02DQ_ACCEL_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
|
||||
.odr = {
|
||||
.addr = ST_ACCEL_7_ODR_ADDR,
|
||||
.mask = ST_ACCEL_7_ODR_MASK,
|
||||
.odr_avl = {
|
||||
{ 280, ST_ACCEL_7_ODR_AVL_280HZ_VAL, },
|
||||
{ 560, ST_ACCEL_7_ODR_AVL_560HZ_VAL, },
|
||||
{ 1120, ST_ACCEL_7_ODR_AVL_1120HZ_VAL, },
|
||||
{ 4480, ST_ACCEL_7_ODR_AVL_4480HZ_VAL, },
|
||||
},
|
||||
},
|
||||
.pw = {
|
||||
.addr = ST_ACCEL_7_PW_ADDR,
|
||||
.mask = ST_ACCEL_7_PW_MASK,
|
||||
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
||||
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
||||
},
|
||||
.enable_axis = {
|
||||
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
|
||||
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
|
||||
},
|
||||
.fs = {
|
||||
.fs_avl = {
|
||||
[0] = {
|
||||
.num = ST_ACCEL_FS_AVL_2G,
|
||||
.gain = ST_ACCEL_7_FS_AVL_2_GAIN,
|
||||
},
|
||||
},
|
||||
},
|
||||
/*
|
||||
* The part has a BDU bit but if set the data is never
|
||||
* updated so don't set it.
|
||||
*/
|
||||
.bdu = {
|
||||
},
|
||||
.drdy_irq = {
|
||||
.addr = ST_ACCEL_7_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_7_DRDY_IRQ_INT1_MASK,
|
||||
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
|
||||
},
|
||||
.multi_read_bit = ST_ACCEL_7_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static int st_accel_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -80,6 +80,10 @@ static const struct of_device_id st_accel_of_match[] = {
|
||||
.compatible = "st,h3lis331dl-accel",
|
||||
.data = H3LIS331DL_DRIVER_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,lis3l02dq",
|
||||
.data = LIS3L02DQ_ACCEL_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_accel_of_match);
|
||||
@ -130,6 +134,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
|
||||
{ LSM330_ACCEL_DEV_NAME },
|
||||
{ LSM303AGR_ACCEL_DEV_NAME },
|
||||
{ LIS2DH12_ACCEL_DEV_NAME },
|
||||
{ LIS3L02DQ_ACCEL_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
|
||||
|
@ -59,6 +59,7 @@ static const struct spi_device_id st_accel_id_table[] = {
|
||||
{ LSM330_ACCEL_DEV_NAME },
|
||||
{ LSM303AGR_ACCEL_DEV_NAME },
|
||||
{ LIS2DH12_ACCEL_DEV_NAME },
|
||||
{ LIS3L02DQ_ACCEL_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
|
||||
|
@ -153,6 +153,18 @@ config AXP288_ADC
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called axp288_adc.
|
||||
|
||||
config BCM_IPROC_ADC
|
||||
tristate "Broadcom IPROC ADC driver"
|
||||
depends on ARCH_BCM_IPROC || COMPILE_TEST
|
||||
depends on MFD_SYSCON
|
||||
default ARCH_BCM_CYGNUS
|
||||
help
|
||||
Say Y here if you want to add support for the Broadcom static
|
||||
ADC driver.
|
||||
|
||||
Broadcom iProc ADC driver. Broadcom iProc ADC controller has 8
|
||||
channels. The driver allows the user to read voltage values.
|
||||
|
||||
config BERLIN2_ADC
|
||||
tristate "Marvell Berlin2 ADC driver"
|
||||
depends on ARCH_BERLIN
|
||||
|
@ -16,6 +16,7 @@ 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_BCM_IPROC_ADC) += bcm_iproc_adc.o
|
||||
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
|
||||
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
|
||||
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
|
||||
|
@ -440,6 +440,7 @@ static int ad7266_probe(struct spi_device *spi)
|
||||
st->spi = spi;
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &ad7266_info;
|
||||
|
@ -115,7 +115,7 @@ static irqreturn_t ad7291_event_handler(int irq, void *private)
|
||||
u16 t_status, v_status;
|
||||
u16 command;
|
||||
int i;
|
||||
s64 timestamp = iio_get_time_ns();
|
||||
s64 timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status))
|
||||
return IRQ_HANDLED;
|
||||
@ -505,6 +505,7 @@ static int ad7291_probe(struct i2c_client *client,
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad7291_channels);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->info = &ad7291_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
|
@ -163,7 +163,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -315,6 +315,7 @@ static int ad7298_probe(struct spi_device *spi)
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ad7298_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad7298_channels);
|
||||
|
@ -70,7 +70,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
@ -227,6 +227,7 @@ static int ad7476_probe(struct spi_device *spi)
|
||||
|
||||
/* Establish that the iio_dev is a child of the spi device */
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->chip_info->channel;
|
||||
|
@ -375,6 +375,7 @@ static int ad7791_probe(struct spi_device *spi)
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->info->channels;
|
||||
|
@ -784,6 +784,7 @@ static int ad7793_probe(struct spi_device *spi)
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->chip_info->channels;
|
||||
|
@ -122,7 +122,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->data,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
@ -264,6 +264,7 @@ static int ad7887_probe(struct spi_device *spi)
|
||||
|
||||
/* Estabilish that the iio_dev is a child of the spi device */
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->info = &ad7887_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -288,6 +288,7 @@ static int ad7923_probe(struct spi_device *spi)
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = info->channels;
|
||||
indio_dev->num_channels = info->num_channels;
|
||||
|
@ -212,7 +212,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
|
||||
goto out;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
@ -502,7 +502,7 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
|
||||
(i >> 1),
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
done:
|
||||
@ -806,6 +806,7 @@ static int ad799x_probe(struct i2c_client *client,
|
||||
st->client = client;
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->info = st->chip_config->info;
|
||||
|
||||
|
644
drivers/iio/adc/bcm_iproc_adc.c
Normal file
644
drivers/iio/adc/bcm_iproc_adc.c
Normal file
@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Copyright 2016 Broadcom
|
||||
*
|
||||
* 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 (the "GPL").
|
||||
*
|
||||
* 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 version 2 (GPLv2) for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 (GPLv2) along with this source code.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
/* Below Register's are common to IPROC ADC and Touchscreen IP */
|
||||
#define IPROC_REGCTL1 0x00
|
||||
#define IPROC_REGCTL2 0x04
|
||||
#define IPROC_INTERRUPT_THRES 0x08
|
||||
#define IPROC_INTERRUPT_MASK 0x0c
|
||||
#define IPROC_INTERRUPT_STATUS 0x10
|
||||
#define IPROC_ANALOG_CONTROL 0x1c
|
||||
#define IPROC_CONTROLLER_STATUS 0x14
|
||||
#define IPROC_AUX_DATA 0x20
|
||||
#define IPROC_SOFT_BYPASS_CONTROL 0x38
|
||||
#define IPROC_SOFT_BYPASS_DATA 0x3C
|
||||
|
||||
/* IPROC ADC Channel register offsets */
|
||||
#define IPROC_ADC_CHANNEL_REGCTL1 0x800
|
||||
#define IPROC_ADC_CHANNEL_REGCTL2 0x804
|
||||
#define IPROC_ADC_CHANNEL_STATUS 0x808
|
||||
#define IPROC_ADC_CHANNEL_INTERRUPT_STATUS 0x80c
|
||||
#define IPROC_ADC_CHANNEL_INTERRUPT_MASK 0x810
|
||||
#define IPROC_ADC_CHANNEL_DATA 0x814
|
||||
#define IPROC_ADC_CHANNEL_OFFSET 0x20
|
||||
|
||||
/* Bit definitions for IPROC_REGCTL2 */
|
||||
#define IPROC_ADC_AUXIN_SCAN_ENA BIT(0)
|
||||
#define IPROC_ADC_PWR_LDO BIT(5)
|
||||
#define IPROC_ADC_PWR_ADC BIT(4)
|
||||
#define IPROC_ADC_PWR_BG BIT(3)
|
||||
#define IPROC_ADC_CONTROLLER_EN BIT(17)
|
||||
|
||||
/* Bit definitions for IPROC_INTERRUPT_MASK and IPROC_INTERRUPT_STATUS */
|
||||
#define IPROC_ADC_AUXDATA_RDY_INTR BIT(3)
|
||||
#define IPROC_ADC_INTR 9
|
||||
#define IPROC_ADC_INTR_MASK (0xFF << IPROC_ADC_INTR)
|
||||
|
||||
/* Bit definitions for IPROC_ANALOG_CONTROL */
|
||||
#define IPROC_ADC_CHANNEL_SEL 11
|
||||
#define IPROC_ADC_CHANNEL_SEL_MASK (0x7 << IPROC_ADC_CHANNEL_SEL)
|
||||
|
||||
/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL1 */
|
||||
#define IPROC_ADC_CHANNEL_ROUNDS 0x2
|
||||
#define IPROC_ADC_CHANNEL_ROUNDS_MASK (0x3F << IPROC_ADC_CHANNEL_ROUNDS)
|
||||
#define IPROC_ADC_CHANNEL_MODE 0x1
|
||||
#define IPROC_ADC_CHANNEL_MODE_MASK (0x1 << IPROC_ADC_CHANNEL_MODE)
|
||||
#define IPROC_ADC_CHANNEL_MODE_TDM 0x1
|
||||
#define IPROC_ADC_CHANNEL_MODE_SNAPSHOT 0x0
|
||||
#define IPROC_ADC_CHANNEL_ENABLE 0x0
|
||||
#define IPROC_ADC_CHANNEL_ENABLE_MASK 0x1
|
||||
|
||||
/* Bit definitions for IPROC_ADC_CHANNEL_REGCTL2 */
|
||||
#define IPROC_ADC_CHANNEL_WATERMARK 0x0
|
||||
#define IPROC_ADC_CHANNEL_WATERMARK_MASK \
|
||||
(0x3F << IPROC_ADC_CHANNEL_WATERMARK)
|
||||
|
||||
#define IPROC_ADC_WATER_MARK_LEVEL 0x1
|
||||
|
||||
/* Bit definitions for IPROC_ADC_CHANNEL_STATUS */
|
||||
#define IPROC_ADC_CHANNEL_DATA_LOST 0x0
|
||||
#define IPROC_ADC_CHANNEL_DATA_LOST_MASK \
|
||||
(0x0 << IPROC_ADC_CHANNEL_DATA_LOST)
|
||||
#define IPROC_ADC_CHANNEL_VALID_ENTERIES 0x1
|
||||
#define IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK \
|
||||
(0xFF << IPROC_ADC_CHANNEL_VALID_ENTERIES)
|
||||
#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES 0x9
|
||||
#define IPROC_ADC_CHANNEL_TOTAL_ENTERIES_MASK \
|
||||
(0xFF << IPROC_ADC_CHANNEL_TOTAL_ENTERIES)
|
||||
|
||||
/* Bit definitions for IPROC_ADC_CHANNEL_INTERRUPT_MASK */
|
||||
#define IPROC_ADC_CHANNEL_WTRMRK_INTR 0x0
|
||||
#define IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK \
|
||||
(0x1 << IPROC_ADC_CHANNEL_WTRMRK_INTR)
|
||||
#define IPROC_ADC_CHANNEL_FULL_INTR 0x1
|
||||
#define IPROC_ADC_CHANNEL_FULL_INTR_MASK \
|
||||
(0x1 << IPROC_ADC_IPROC_ADC_CHANNEL_FULL_INTR)
|
||||
#define IPROC_ADC_CHANNEL_EMPTY_INTR 0x2
|
||||
#define IPROC_ADC_CHANNEL_EMPTY_INTR_MASK \
|
||||
(0x1 << IPROC_ADC_CHANNEL_EMPTY_INTR)
|
||||
|
||||
#define IPROC_ADC_WATER_MARK_INTR_ENABLE 0x1
|
||||
|
||||
/* Number of time to retry a set of the interrupt mask reg */
|
||||
#define IPROC_ADC_INTMASK_RETRY_ATTEMPTS 10
|
||||
|
||||
#define IPROC_ADC_READ_TIMEOUT (HZ*2)
|
||||
|
||||
#define iproc_adc_dbg_reg(dev, priv, reg) \
|
||||
do { \
|
||||
u32 val; \
|
||||
regmap_read(priv->regmap, reg, &val); \
|
||||
dev_dbg(dev, "%20s= 0x%08x\n", #reg, val); \
|
||||
} while (0)
|
||||
|
||||
struct iproc_adc_priv {
|
||||
struct regmap *regmap;
|
||||
struct clk *adc_clk;
|
||||
struct mutex mutex;
|
||||
int irqno;
|
||||
int chan_val;
|
||||
int chan_id;
|
||||
struct completion completion;
|
||||
};
|
||||
|
||||
static void iproc_adc_reg_dump(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct device *dev = &indio_dev->dev;
|
||||
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
|
||||
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL1);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_REGCTL2);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_THRES);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_MASK);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_INTERRUPT_STATUS);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_CONTROLLER_STATUS);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_ANALOG_CONTROL);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_AUX_DATA);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_CONTROL);
|
||||
iproc_adc_dbg_reg(dev, adc_priv, IPROC_SOFT_BYPASS_DATA);
|
||||
}
|
||||
|
||||
static irqreturn_t iproc_adc_interrupt_handler(int irq, void *data)
|
||||
{
|
||||
u32 channel_intr_status;
|
||||
u32 intr_status;
|
||||
u32 intr_mask;
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
|
||||
|
||||
/*
|
||||
* This interrupt is shared with the touchscreen driver.
|
||||
* Make sure this interrupt is intended for us.
|
||||
* Handle only ADC channel specific interrupts.
|
||||
*/
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &intr_mask);
|
||||
intr_status = intr_status & intr_mask;
|
||||
channel_intr_status = (intr_status & IPROC_ADC_INTR_MASK) >>
|
||||
IPROC_ADC_INTR;
|
||||
if (channel_intr_status)
|
||||
return IRQ_WAKE_THREAD;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static irqreturn_t iproc_adc_interrupt_thread(int irq, void *data)
|
||||
{
|
||||
irqreturn_t retval = IRQ_NONE;
|
||||
struct iproc_adc_priv *adc_priv;
|
||||
struct iio_dev *indio_dev = data;
|
||||
unsigned int valid_entries;
|
||||
u32 intr_status;
|
||||
u32 intr_channels;
|
||||
u32 channel_status;
|
||||
u32 ch_intr_status;
|
||||
|
||||
adc_priv = iio_priv(indio_dev);
|
||||
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_STATUS, &intr_status);
|
||||
dev_dbg(&indio_dev->dev, "iproc_adc_interrupt_thread(),INTRPT_STS:%x\n",
|
||||
intr_status);
|
||||
|
||||
intr_channels = (intr_status & IPROC_ADC_INTR_MASK) >> IPROC_ADC_INTR;
|
||||
if (intr_channels) {
|
||||
regmap_read(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
|
||||
IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id,
|
||||
&ch_intr_status);
|
||||
|
||||
if (ch_intr_status & IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK) {
|
||||
regmap_read(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_STATUS +
|
||||
IPROC_ADC_CHANNEL_OFFSET *
|
||||
adc_priv->chan_id,
|
||||
&channel_status);
|
||||
|
||||
valid_entries = ((channel_status &
|
||||
IPROC_ADC_CHANNEL_VALID_ENTERIES_MASK) >>
|
||||
IPROC_ADC_CHANNEL_VALID_ENTERIES);
|
||||
if (valid_entries >= 1) {
|
||||
regmap_read(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_DATA +
|
||||
IPROC_ADC_CHANNEL_OFFSET *
|
||||
adc_priv->chan_id,
|
||||
&adc_priv->chan_val);
|
||||
complete(&adc_priv->completion);
|
||||
} else {
|
||||
dev_err(&indio_dev->dev,
|
||||
"No data rcvd on channel %d\n",
|
||||
adc_priv->chan_id);
|
||||
}
|
||||
regmap_write(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_INTERRUPT_MASK +
|
||||
IPROC_ADC_CHANNEL_OFFSET *
|
||||
adc_priv->chan_id,
|
||||
(ch_intr_status &
|
||||
~(IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK)));
|
||||
}
|
||||
regmap_write(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
|
||||
IPROC_ADC_CHANNEL_OFFSET * adc_priv->chan_id,
|
||||
ch_intr_status);
|
||||
regmap_write(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
|
||||
intr_channels);
|
||||
retval = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int iproc_adc_do_read(struct iio_dev *indio_dev,
|
||||
int channel,
|
||||
u16 *p_adc_data)
|
||||
{
|
||||
int read_len = 0;
|
||||
u32 val;
|
||||
u32 mask;
|
||||
u32 val_check;
|
||||
int failed_cnt = 0;
|
||||
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&adc_priv->mutex);
|
||||
|
||||
/*
|
||||
* After a read is complete the ADC interrupts will be disabled so
|
||||
* we can assume this section of code is safe from interrupts.
|
||||
*/
|
||||
adc_priv->chan_val = -1;
|
||||
adc_priv->chan_id = channel;
|
||||
|
||||
reinit_completion(&adc_priv->completion);
|
||||
/* Clear any pending interrupt */
|
||||
regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
|
||||
IPROC_ADC_INTR_MASK | IPROC_ADC_AUXDATA_RDY_INTR,
|
||||
((0x0 << channel) << IPROC_ADC_INTR) |
|
||||
IPROC_ADC_AUXDATA_RDY_INTR);
|
||||
|
||||
/* Configure channel for snapshot mode and enable */
|
||||
val = (BIT(IPROC_ADC_CHANNEL_ROUNDS) |
|
||||
(IPROC_ADC_CHANNEL_MODE_SNAPSHOT << IPROC_ADC_CHANNEL_MODE) |
|
||||
(0x1 << IPROC_ADC_CHANNEL_ENABLE));
|
||||
|
||||
mask = IPROC_ADC_CHANNEL_ROUNDS_MASK | IPROC_ADC_CHANNEL_MODE_MASK |
|
||||
IPROC_ADC_CHANNEL_ENABLE_MASK;
|
||||
regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL1 +
|
||||
IPROC_ADC_CHANNEL_OFFSET * channel),
|
||||
mask, val);
|
||||
|
||||
/* Set the Watermark for a channel */
|
||||
regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_REGCTL2 +
|
||||
IPROC_ADC_CHANNEL_OFFSET * channel),
|
||||
IPROC_ADC_CHANNEL_WATERMARK_MASK,
|
||||
0x1);
|
||||
|
||||
/* Enable water mark interrupt */
|
||||
regmap_update_bits(adc_priv->regmap, (IPROC_ADC_CHANNEL_INTERRUPT_MASK +
|
||||
IPROC_ADC_CHANNEL_OFFSET *
|
||||
channel),
|
||||
IPROC_ADC_CHANNEL_WTRMRK_INTR_MASK,
|
||||
IPROC_ADC_WATER_MARK_INTR_ENABLE);
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val);
|
||||
|
||||
/* Enable ADC interrupt for a channel */
|
||||
val |= (BIT(channel) << IPROC_ADC_INTR);
|
||||
regmap_write(adc_priv->regmap, IPROC_INTERRUPT_MASK, val);
|
||||
|
||||
/*
|
||||
* There seems to be a very rare issue where writing to this register
|
||||
* does not take effect. To work around the issue we will try multiple
|
||||
* writes. In total we will spend about 10*10 = 100 us attempting this.
|
||||
* Testing has shown that this may loop a few time, but we have never
|
||||
* hit the full count.
|
||||
*/
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
|
||||
while (val_check != val) {
|
||||
failed_cnt++;
|
||||
|
||||
if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS)
|
||||
break;
|
||||
|
||||
udelay(10);
|
||||
regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK,
|
||||
IPROC_ADC_INTR_MASK,
|
||||
((0x1 << channel) <<
|
||||
IPROC_ADC_INTR));
|
||||
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
|
||||
}
|
||||
|
||||
if (failed_cnt) {
|
||||
dev_dbg(&indio_dev->dev,
|
||||
"IntMask failed (%d times)", failed_cnt);
|
||||
if (failed_cnt > IPROC_ADC_INTMASK_RETRY_ATTEMPTS) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"IntMask set failed. Read will likely fail.");
|
||||
read_len = -EIO;
|
||||
goto adc_err;
|
||||
};
|
||||
}
|
||||
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);
|
||||
|
||||
if (wait_for_completion_timeout(&adc_priv->completion,
|
||||
IPROC_ADC_READ_TIMEOUT) > 0) {
|
||||
|
||||
/* Only the lower 16 bits are relevant */
|
||||
*p_adc_data = adc_priv->chan_val & 0xFFFF;
|
||||
read_len = sizeof(*p_adc_data);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* We never got the interrupt, something went wrong.
|
||||
* Perhaps the interrupt may still be coming, we do not want
|
||||
* that now. Lets disable the ADC interrupt, and clear the
|
||||
* status to put it back in to normal state.
|
||||
*/
|
||||
read_len = -ETIMEDOUT;
|
||||
goto adc_err;
|
||||
}
|
||||
mutex_unlock(&adc_priv->mutex);
|
||||
|
||||
return read_len;
|
||||
|
||||
adc_err:
|
||||
regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_MASK,
|
||||
IPROC_ADC_INTR_MASK,
|
||||
((0x0 << channel) << IPROC_ADC_INTR));
|
||||
|
||||
regmap_update_bits(adc_priv->regmap, IPROC_INTERRUPT_STATUS,
|
||||
IPROC_ADC_INTR_MASK,
|
||||
((0x0 << channel) << IPROC_ADC_INTR));
|
||||
|
||||
dev_err(&indio_dev->dev, "Timed out waiting for ADC data!\n");
|
||||
iproc_adc_reg_dump(indio_dev);
|
||||
mutex_unlock(&adc_priv->mutex);
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
static int iproc_adc_enable(struct iio_dev *indio_dev)
|
||||
{
|
||||
u32 val;
|
||||
u32 channel_id;
|
||||
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* Set i_amux = 3b'000, select channel 0 */
|
||||
ret = regmap_update_bits(adc_priv->regmap, IPROC_ANALOG_CONTROL,
|
||||
IPROC_ADC_CHANNEL_SEL_MASK, 0);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to write IPROC_ANALOG_CONTROL %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
adc_priv->chan_val = -1;
|
||||
|
||||
/*
|
||||
* PWR up LDO, ADC, and Band Gap (0 to enable)
|
||||
* Also enable ADC controller (set high)
|
||||
*/
|
||||
ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to read IPROC_REGCTL2 %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val &= ~(IPROC_ADC_PWR_LDO | IPROC_ADC_PWR_ADC | IPROC_ADC_PWR_BG);
|
||||
|
||||
ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to write IPROC_REGCTL2 %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to read IPROC_REGCTL2 %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val |= IPROC_ADC_CONTROLLER_EN;
|
||||
ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to write IPROC_REGCTL2 %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (channel_id = 0; channel_id < indio_dev->num_channels;
|
||||
channel_id++) {
|
||||
ret = regmap_write(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_INTERRUPT_MASK +
|
||||
IPROC_ADC_CHANNEL_OFFSET * channel_id, 0);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to write ADC_CHANNEL_INTERRUPT_MASK %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(adc_priv->regmap,
|
||||
IPROC_ADC_CHANNEL_INTERRUPT_STATUS +
|
||||
IPROC_ADC_CHANNEL_OFFSET * channel_id, 0);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to write ADC_CHANNEL_INTERRUPT_STATUS %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iproc_adc_disable(struct iio_dev *indio_dev)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
|
||||
|
||||
ret = regmap_read(adc_priv->regmap, IPROC_REGCTL2, &val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to read IPROC_REGCTL2 %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
val &= ~IPROC_ADC_CONTROLLER_EN;
|
||||
ret = regmap_write(adc_priv->regmap, IPROC_REGCTL2, val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to write IPROC_REGCTL2 %d\n", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int iproc_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
int *val2,
|
||||
long mask)
|
||||
{
|
||||
u16 adc_data;
|
||||
int err;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
err = iproc_adc_do_read(indio_dev, chan->channel, &adc_data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
*val = adc_data;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
*val = 1800;
|
||||
*val2 = 10;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info iproc_adc_iio_info = {
|
||||
.read_raw = &iproc_adc_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define IPROC_ADC_CHANNEL(_index, _id) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = _index, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.datasheet_name = _id, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec iproc_adc_iio_channels[] = {
|
||||
IPROC_ADC_CHANNEL(0, "adc0"),
|
||||
IPROC_ADC_CHANNEL(1, "adc1"),
|
||||
IPROC_ADC_CHANNEL(2, "adc2"),
|
||||
IPROC_ADC_CHANNEL(3, "adc3"),
|
||||
IPROC_ADC_CHANNEL(4, "adc4"),
|
||||
IPROC_ADC_CHANNEL(5, "adc5"),
|
||||
IPROC_ADC_CHANNEL(6, "adc6"),
|
||||
IPROC_ADC_CHANNEL(7, "adc7"),
|
||||
};
|
||||
|
||||
static int iproc_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iproc_adc_priv *adc_priv;
|
||||
struct iio_dev *indio_dev = NULL;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(*adc_priv));
|
||||
if (!indio_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate iio device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
adc_priv = iio_priv(indio_dev);
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
mutex_init(&adc_priv->mutex);
|
||||
|
||||
init_completion(&adc_priv->completion);
|
||||
|
||||
adc_priv->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"adc-syscon");
|
||||
if (IS_ERR(adc_priv->regmap)) {
|
||||
dev_err(&pdev->dev, "failed to get handle for tsc syscon\n");
|
||||
ret = PTR_ERR(adc_priv->regmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
adc_priv->adc_clk = devm_clk_get(&pdev->dev, "tsc_clk");
|
||||
if (IS_ERR(adc_priv->adc_clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed getting clock tsc_clk\n");
|
||||
ret = PTR_ERR(adc_priv->adc_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
adc_priv->irqno = platform_get_irq(pdev, 0);
|
||||
if (adc_priv->irqno <= 0) {
|
||||
dev_err(&pdev->dev, "platform_get_irq failed\n");
|
||||
ret = -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
|
||||
IPROC_ADC_AUXIN_SCAN_ENA, 0);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to write IPROC_REGCTL2 %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, adc_priv->irqno,
|
||||
iproc_adc_interrupt_thread,
|
||||
iproc_adc_interrupt_handler,
|
||||
IRQF_SHARED, "iproc-adc", indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request_irq error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(adc_priv->adc_clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"clk_prepare_enable failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iproc_adc_enable(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable adc %d\n", ret);
|
||||
goto err_adc_enable;
|
||||
}
|
||||
|
||||
indio_dev->name = "iproc-static-adc";
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->dev.of_node = pdev->dev.of_node;
|
||||
indio_dev->info = &iproc_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = iproc_adc_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(iproc_adc_iio_channels);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "iio_device_register failed:err %d\n", ret);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
iproc_adc_disable(indio_dev);
|
||||
err_adc_enable:
|
||||
clk_disable_unprepare(adc_priv->adc_clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iproc_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct iproc_adc_priv *adc_priv = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iproc_adc_disable(indio_dev);
|
||||
clk_disable_unprepare(adc_priv->adc_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id iproc_adc_of_match[] = {
|
||||
{.compatible = "brcm,iproc-static-adc", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, iproc_adc_of_match);
|
||||
|
||||
static struct platform_driver iproc_adc_driver = {
|
||||
.probe = iproc_adc_probe,
|
||||
.remove = iproc_adc_remove,
|
||||
.driver = {
|
||||
.name = "iproc-static-adc",
|
||||
.of_match_table = of_match_ptr(iproc_adc_of_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(iproc_adc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Broadcom iProc ADC controller driver");
|
||||
MODULE_AUTHOR("Raveendra Padasalagi <raveendra.padasalagi@broadcom.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -186,7 +186,7 @@ done:
|
||||
|
||||
if (!sample_invalid)
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -400,7 +400,7 @@ static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
|
||||
iio_push_event(idev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
|
||||
IIO_EV_TYPE_THRESH, dir),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(idev));
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,6 +455,7 @@ static int hi8435_probe(struct spi_device *spi)
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
idev->dev.parent = &spi->dev;
|
||||
idev->dev.of_node = spi->dev.of_node;
|
||||
idev->name = spi_get_device_id(spi)->name;
|
||||
idev->modes = INDIO_DIRECT_MODE;
|
||||
idev->info = &hi8435_info;
|
||||
|
@ -465,7 +465,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
||||
s64 time_a, time_b;
|
||||
unsigned int alert;
|
||||
|
||||
time_a = iio_get_time_ns();
|
||||
time_a = iio_get_time_ns(indio_dev);
|
||||
|
||||
/*
|
||||
* Because the timer thread and the chip conversion clock
|
||||
@ -504,7 +504,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
||||
data[i++] = val;
|
||||
}
|
||||
|
||||
time_b = iio_get_time_ns();
|
||||
time_b = iio_get_time_ns(indio_dev);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
(unsigned int *)data, time_a);
|
||||
@ -554,7 +554,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
|
||||
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
|
||||
chip->allow_async_readout);
|
||||
|
||||
chip->prev_ns = iio_get_time_ns();
|
||||
chip->prev_ns = iio_get_time_ns(indio_dev);
|
||||
|
||||
chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
|
||||
"%s:%d-%uus", indio_dev->name, indio_dev->id,
|
||||
@ -691,6 +691,7 @@ static int ina2xx_probe(struct i2c_client *client,
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->channels = ina2xx_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ina2xx_channels);
|
||||
indio_dev->name = id->name;
|
||||
|
@ -426,6 +426,7 @@ static int max1027_probe(struct spi_device *spi)
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->info = &max1027_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->info->channels;
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -788,7 +790,7 @@ static irqreturn_t max1363_event_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct max1363_state *st = iio_priv(indio_dev);
|
||||
s64 timestamp = iio_get_time_ns();
|
||||
s64 timestamp = iio_get_time_ns(indio_dev);
|
||||
unsigned long mask, loc;
|
||||
u8 rx;
|
||||
u8 tx[2] = { st->setupbyte,
|
||||
@ -1506,7 +1508,8 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
|
||||
if (b_sent < 0)
|
||||
goto done_free;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, rxbuf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, rxbuf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done_free:
|
||||
kfree(rxbuf);
|
||||
@ -1516,6 +1519,56 @@ done:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
#define MAX1363_COMPATIBLE(of_compatible, cfg) { \
|
||||
.compatible = of_compatible, \
|
||||
.data = &max1363_chip_info_tbl[cfg], \
|
||||
}
|
||||
|
||||
static const struct of_device_id max1363_of_match[] = {
|
||||
MAX1363_COMPATIBLE("maxim,max1361", max1361),
|
||||
MAX1363_COMPATIBLE("maxim,max1362", max1362),
|
||||
MAX1363_COMPATIBLE("maxim,max1363", max1363),
|
||||
MAX1363_COMPATIBLE("maxim,max1364", max1364),
|
||||
MAX1363_COMPATIBLE("maxim,max1036", max1036),
|
||||
MAX1363_COMPATIBLE("maxim,max1037", max1037),
|
||||
MAX1363_COMPATIBLE("maxim,max1038", max1038),
|
||||
MAX1363_COMPATIBLE("maxim,max1039", max1039),
|
||||
MAX1363_COMPATIBLE("maxim,max1136", max1136),
|
||||
MAX1363_COMPATIBLE("maxim,max1137", max1137),
|
||||
MAX1363_COMPATIBLE("maxim,max1138", max1138),
|
||||
MAX1363_COMPATIBLE("maxim,max1139", max1139),
|
||||
MAX1363_COMPATIBLE("maxim,max1236", max1236),
|
||||
MAX1363_COMPATIBLE("maxim,max1237", max1237),
|
||||
MAX1363_COMPATIBLE("maxim,max1238", max1238),
|
||||
MAX1363_COMPATIBLE("maxim,max1239", max1239),
|
||||
MAX1363_COMPATIBLE("maxim,max11600", max11600),
|
||||
MAX1363_COMPATIBLE("maxim,max11601", max11601),
|
||||
MAX1363_COMPATIBLE("maxim,max11602", max11602),
|
||||
MAX1363_COMPATIBLE("maxim,max11603", max11603),
|
||||
MAX1363_COMPATIBLE("maxim,max11604", max11604),
|
||||
MAX1363_COMPATIBLE("maxim,max11605", max11605),
|
||||
MAX1363_COMPATIBLE("maxim,max11606", max11606),
|
||||
MAX1363_COMPATIBLE("maxim,max11607", max11607),
|
||||
MAX1363_COMPATIBLE("maxim,max11608", max11608),
|
||||
MAX1363_COMPATIBLE("maxim,max11609", max11609),
|
||||
MAX1363_COMPATIBLE("maxim,max11610", max11610),
|
||||
MAX1363_COMPATIBLE("maxim,max11611", max11611),
|
||||
MAX1363_COMPATIBLE("maxim,max11612", max11612),
|
||||
MAX1363_COMPATIBLE("maxim,max11613", max11613),
|
||||
MAX1363_COMPATIBLE("maxim,max11614", max11614),
|
||||
MAX1363_COMPATIBLE("maxim,max11615", max11615),
|
||||
MAX1363_COMPATIBLE("maxim,max11616", max11616),
|
||||
MAX1363_COMPATIBLE("maxim,max11617", max11617),
|
||||
MAX1363_COMPATIBLE("maxim,max11644", max11644),
|
||||
MAX1363_COMPATIBLE("maxim,max11645", max11645),
|
||||
MAX1363_COMPATIBLE("maxim,max11646", max11646),
|
||||
MAX1363_COMPATIBLE("maxim,max11647", max11647),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static int max1363_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -1523,6 +1576,7 @@ static int max1363_probe(struct i2c_client *client,
|
||||
struct max1363_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct regulator *vref;
|
||||
const struct of_device_id *match;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev,
|
||||
sizeof(struct max1363_state));
|
||||
@ -1549,7 +1603,12 @@ static int max1363_probe(struct i2c_client *client,
|
||||
/* this is only used for device removal purposes */
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
st->chip_info = &max1363_chip_info_tbl[id->driver_data];
|
||||
match = of_match_device(of_match_ptr(max1363_of_match),
|
||||
&client->dev);
|
||||
if (match)
|
||||
st->chip_info = of_device_get_match_data(&client->dev);
|
||||
else
|
||||
st->chip_info = &max1363_chip_info_tbl[id->driver_data];
|
||||
st->client = client;
|
||||
|
||||
st->vref_uv = st->chip_info->int_vref_mv * 1000;
|
||||
@ -1587,6 +1646,7 @@ static int max1363_probe(struct i2c_client *client,
|
||||
|
||||
/* Establish that the iio_dev is a child of the i2c device */
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->channels = st->chip_info->channels;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
@ -1692,6 +1752,7 @@ MODULE_DEVICE_TABLE(i2c, max1363_id);
|
||||
static struct i2c_driver max1363_driver = {
|
||||
.driver = {
|
||||
.name = "max1363",
|
||||
.of_match_table = of_match_ptr(max1363_of_match),
|
||||
},
|
||||
.probe = max1363_probe,
|
||||
.remove = max1363_remove,
|
||||
|
@ -308,6 +308,7 @@ static int mcp320x_probe(struct spi_device *spi)
|
||||
adc->spi = spi;
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mcp320x_info;
|
||||
|
@ -352,6 +352,7 @@ static int mcp3422_probe(struct i2c_client *client,
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->name = dev_name(&client->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mcp3422_info;
|
||||
|
@ -433,6 +433,7 @@ static int nau7802_probe(struct i2c_client *client,
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->name = dev_name(&client->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &nau7802_info;
|
||||
|
@ -139,7 +139,8 @@ static irqreturn_t adc081c_trigger_handler(int irq, void *p)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
buf[0] = ret;
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
@ -185,6 +186,7 @@ static int adc081c_probe(struct i2c_client *client,
|
||||
return err;
|
||||
|
||||
iio->dev.parent = &client->dev;
|
||||
iio->dev.of_node = client->dev.of_node;
|
||||
iio->name = dev_name(&client->dev);
|
||||
iio->modes = INDIO_DIRECT_MODE;
|
||||
iio->info = &adc081c_info;
|
||||
|
@ -194,6 +194,7 @@ static int adc0832_probe(struct spi_device *spi)
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->info = &adc0832_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
|
@ -150,6 +150,7 @@ static int adc128_probe(struct spi_device *spi)
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &adc128_info;
|
||||
|
@ -288,7 +288,8 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
|
||||
buf[0] = res;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -585,6 +586,7 @@ static int ads1015_probe(struct i2c_client *client,
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->dev.of_node = client->dev.of_node;
|
||||
indio_dev->name = ADS1015_DRV_NAME;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
|
@ -421,6 +421,7 @@ static int ads8688_probe(struct spi_device *spi)
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->dev.of_node = spi->dev.of_node;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->chip_info->channels;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
|
@ -594,7 +594,8 @@ static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
info->buffer[0] = info->value;
|
||||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
info->buffer, iio_get_time_ns());
|
||||
info->buffer,
|
||||
iio_get_time_ns(indio_dev));
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
} else
|
||||
complete(&info->completion);
|
||||
|
@ -46,7 +46,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
|
||||
IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
} else {
|
||||
/*
|
||||
* For other channels we don't know whether it is a upper or
|
||||
@ -56,7 +56,7 @@ static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
|
||||
IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
|
||||
|
||||
if (!ret)
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
|
@ -24,30 +24,29 @@
|
||||
|
||||
static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
|
||||
{
|
||||
int i, len;
|
||||
int total = 0;
|
||||
int i;
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
unsigned int num_data_channels = sdata->num_data_channels;
|
||||
|
||||
for (i = 0; i < num_data_channels; i++) {
|
||||
unsigned int bytes_to_read;
|
||||
for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) {
|
||||
const struct iio_chan_spec *channel = &indio_dev->channels[i];
|
||||
unsigned int bytes_to_read = channel->scan_type.realbits >> 3;
|
||||
unsigned int storage_bytes =
|
||||
channel->scan_type.storagebits >> 3;
|
||||
|
||||
if (test_bit(i, indio_dev->active_scan_mask)) {
|
||||
bytes_to_read = indio_dev->channels[i].scan_type.storagebits >> 3;
|
||||
len = sdata->tf->read_multiple_byte(&sdata->tb,
|
||||
sdata->dev, indio_dev->channels[i].address,
|
||||
bytes_to_read,
|
||||
buf + total, sdata->multiread_bit);
|
||||
buf = PTR_ALIGN(buf, storage_bytes);
|
||||
if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
|
||||
channel->address,
|
||||
bytes_to_read, buf,
|
||||
sdata->multiread_bit) <
|
||||
bytes_to_read)
|
||||
return -EIO;
|
||||
|
||||
if (len < bytes_to_read)
|
||||
return -EIO;
|
||||
|
||||
/* Advance the buffer pointer */
|
||||
total += len;
|
||||
}
|
||||
/* Advance the buffer pointer */
|
||||
buf += storage_bytes;
|
||||
}
|
||||
|
||||
return total;
|
||||
return 0;
|
||||
}
|
||||
|
||||
irqreturn_t st_sensors_trigger_handler(int irq, void *p)
|
||||
@ -58,11 +57,16 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
s64 timestamp;
|
||||
|
||||
/* If we do timetamping here, do it before reading the values */
|
||||
/*
|
||||
* If we do timetamping here, do it before reading the values, because
|
||||
* once we've read the values, new interrupts can occur (when using
|
||||
* the hardware trigger) and the hw_timestamp may get updated.
|
||||
* By storing it in a local variable first, we are safe.
|
||||
*/
|
||||
if (sdata->hw_irq_trigger)
|
||||
timestamp = sdata->hw_timestamp;
|
||||
else
|
||||
timestamp = iio_get_time_ns();
|
||||
timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
|
||||
if (len < 0)
|
||||
|
@ -490,7 +490,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
|
||||
int err;
|
||||
u8 *outdata;
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
unsigned int byte_for_channel = ch->scan_type.storagebits >> 3;
|
||||
unsigned int byte_for_channel = ch->scan_type.realbits >> 3;
|
||||
|
||||
outdata = kmalloc(byte_for_channel, GFP_KERNEL);
|
||||
if (!outdata)
|
||||
@ -550,7 +550,7 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
|
||||
int num_sensors_list,
|
||||
const struct st_sensor_settings *sensor_settings)
|
||||
{
|
||||
int i, n, err;
|
||||
int i, n, err = 0;
|
||||
u8 wai;
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
|
||||
@ -570,17 +570,21 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
|
||||
sensor_settings[i].wai_addr, &wai);
|
||||
if (err < 0) {
|
||||
dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
|
||||
return err;
|
||||
}
|
||||
if (sensor_settings[i].wai_addr) {
|
||||
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
|
||||
sensor_settings[i].wai_addr, &wai);
|
||||
if (err < 0) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"failed to read Who-Am-I register.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (sensor_settings[i].wai != wai) {
|
||||
dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n",
|
||||
indio_dev->name, wai);
|
||||
return -EINVAL;
|
||||
if (sensor_settings[i].wai != wai) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"%s: WhoAmI mismatch (0x%x).\n",
|
||||
indio_dev->name, wai);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
sdata->sensor_settings =
|
||||
|
@ -17,6 +17,50 @@
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
#include "st_sensors_core.h"
|
||||
|
||||
/**
|
||||
* st_sensors_new_samples_available() - check if more samples came in
|
||||
* returns:
|
||||
* 0 - no new samples available
|
||||
* 1 - new samples available
|
||||
* negative - error or unknown
|
||||
*/
|
||||
static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
|
||||
struct st_sensor_data *sdata)
|
||||
{
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
/* How would I know if I can't check it? */
|
||||
if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy)
|
||||
return -EINVAL;
|
||||
|
||||
/* No scan mask, no interrupt */
|
||||
if (!indio_dev->active_scan_mask)
|
||||
return 0;
|
||||
|
||||
ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
|
||||
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
|
||||
&status);
|
||||
if (ret < 0) {
|
||||
dev_err(sdata->dev,
|
||||
"error checking samples available\n");
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* the lower bits of .active_scan_mask[0] is directly mapped
|
||||
* to the channels on the sensor: either bit 0 for
|
||||
* one-dimensional sensors, or e.g. x,y,z for accelerometers,
|
||||
* gyroscopes or magnetometers. No sensor use more than 3
|
||||
* channels, so cut the other status bits here.
|
||||
*/
|
||||
status &= 0x07;
|
||||
|
||||
if (status & (u8)indio_dev->active_scan_mask[0])
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_sensors_irq_handler() - top half of the IRQ-based triggers
|
||||
* @irq: irq number
|
||||
@ -29,7 +73,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p)
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
|
||||
/* Get the time stamp as close in time as possible */
|
||||
sdata->hw_timestamp = iio_get_time_ns();
|
||||
sdata->hw_timestamp = iio_get_time_ns(indio_dev);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
@ -43,44 +87,43 @@ irqreturn_t st_sensors_irq_thread(int irq, void *p)
|
||||
struct iio_trigger *trig = p;
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If this trigger is backed by a hardware interrupt and we have a
|
||||
* status register, check if this IRQ came from us
|
||||
* status register, check if this IRQ came from us. Notice that
|
||||
* we will process also if st_sensors_new_samples_available()
|
||||
* returns negative: if we can't check status, then poll
|
||||
* unconditionally.
|
||||
*/
|
||||
if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) {
|
||||
u8 status;
|
||||
|
||||
ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
|
||||
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
|
||||
&status);
|
||||
if (ret < 0) {
|
||||
dev_err(sdata->dev, "could not read channel status\n");
|
||||
goto out_poll;
|
||||
}
|
||||
/*
|
||||
* the lower bits of .active_scan_mask[0] is directly mapped
|
||||
* to the channels on the sensor: either bit 0 for
|
||||
* one-dimensional sensors, or e.g. x,y,z for accelerometers,
|
||||
* gyroscopes or magnetometers. No sensor use more than 3
|
||||
* channels, so cut the other status bits here.
|
||||
*/
|
||||
status &= 0x07;
|
||||
|
||||
/*
|
||||
* If this was not caused by any channels on this sensor,
|
||||
* return IRQ_NONE
|
||||
*/
|
||||
if (!indio_dev->active_scan_mask)
|
||||
return IRQ_NONE;
|
||||
if (!(status & (u8)indio_dev->active_scan_mask[0]))
|
||||
return IRQ_NONE;
|
||||
if (sdata->hw_irq_trigger &&
|
||||
st_sensors_new_samples_available(indio_dev, sdata)) {
|
||||
iio_trigger_poll_chained(p);
|
||||
} else {
|
||||
dev_dbg(sdata->dev, "spurious IRQ\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have proper level IRQs the handler will be re-entered if
|
||||
* the line is still active, so return here and come back in through
|
||||
* the top half if need be.
|
||||
*/
|
||||
if (!sdata->edge_irq)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/*
|
||||
* If we are using egde IRQs, new samples arrived while processing
|
||||
* the IRQ and those may be missed unless we pick them here, so poll
|
||||
* again. If the sensor delivery frequency is very high, this thread
|
||||
* turns into a polled loop handler.
|
||||
*/
|
||||
while (sdata->hw_irq_trigger &&
|
||||
st_sensors_new_samples_available(indio_dev, sdata)) {
|
||||
dev_dbg(sdata->dev, "more samples came in during polling\n");
|
||||
sdata->hw_timestamp = iio_get_time_ns(indio_dev);
|
||||
iio_trigger_poll_chained(p);
|
||||
}
|
||||
|
||||
out_poll:
|
||||
/* It's our IRQ: proceed to handle the register polling */
|
||||
iio_trigger_poll_chained(p);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -107,13 +150,18 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||
* If the IRQ is triggered on falling edge, we need to mark the
|
||||
* interrupt as active low, if the hardware supports this.
|
||||
*/
|
||||
if (irq_trig == IRQF_TRIGGER_FALLING) {
|
||||
switch(irq_trig) {
|
||||
case IRQF_TRIGGER_FALLING:
|
||||
case IRQF_TRIGGER_LOW:
|
||||
if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
|
||||
dev_err(&indio_dev->dev,
|
||||
"falling edge specified for IRQ but hardware "
|
||||
"only support rising edge, will request "
|
||||
"rising edge\n");
|
||||
irq_trig = IRQF_TRIGGER_RISING;
|
||||
"falling/low specified for IRQ "
|
||||
"but hardware only support rising/high: "
|
||||
"will request rising/high\n");
|
||||
if (irq_trig == IRQF_TRIGGER_FALLING)
|
||||
irq_trig = IRQF_TRIGGER_RISING;
|
||||
if (irq_trig == IRQF_TRIGGER_LOW)
|
||||
irq_trig = IRQF_TRIGGER_HIGH;
|
||||
} else {
|
||||
/* Set up INT active low i.e. falling edge */
|
||||
err = st_sensors_write_data_with_mask(indio_dev,
|
||||
@ -122,20 +170,39 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||
if (err < 0)
|
||||
goto iio_trigger_free;
|
||||
dev_info(&indio_dev->dev,
|
||||
"interrupts on the falling edge\n");
|
||||
"interrupts on the falling edge or "
|
||||
"active low level\n");
|
||||
}
|
||||
} else if (irq_trig == IRQF_TRIGGER_RISING) {
|
||||
break;
|
||||
case IRQF_TRIGGER_RISING:
|
||||
dev_info(&indio_dev->dev,
|
||||
"interrupts on the rising edge\n");
|
||||
|
||||
} else {
|
||||
break;
|
||||
case IRQF_TRIGGER_HIGH:
|
||||
dev_info(&indio_dev->dev,
|
||||
"interrupts active high level\n");
|
||||
break;
|
||||
default:
|
||||
/* This is the most preferred mode, if possible */
|
||||
dev_err(&indio_dev->dev,
|
||||
"unsupported IRQ trigger specified (%lx), only "
|
||||
"rising and falling edges supported, enforce "
|
||||
"unsupported IRQ trigger specified (%lx), enforce "
|
||||
"rising edge\n", irq_trig);
|
||||
irq_trig = IRQF_TRIGGER_RISING;
|
||||
}
|
||||
|
||||
/* Tell the interrupt handler that we're dealing with edges */
|
||||
if (irq_trig == IRQF_TRIGGER_FALLING ||
|
||||
irq_trig == IRQF_TRIGGER_RISING)
|
||||
sdata->edge_irq = true;
|
||||
else
|
||||
/*
|
||||
* If we're not using edges (i.e. level interrupts) we
|
||||
* just mask off the IRQ, handle one interrupt, then
|
||||
* if the line is still low, we return to the
|
||||
* interrupt handler top half again and start over.
|
||||
*/
|
||||
irq_trig |= IRQF_ONESHOT;
|
||||
|
||||
/*
|
||||
* If the interrupt pin is Open Drain, by definition this
|
||||
* means that the interrupt line may be shared with other
|
||||
@ -148,9 +215,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||
sdata->sensor_settings->drdy_irq.addr_stat_drdy)
|
||||
irq_trig |= IRQF_SHARED;
|
||||
|
||||
/* Let's create an interrupt thread masking the hard IRQ here */
|
||||
irq_trig |= IRQF_ONESHOT;
|
||||
|
||||
err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
|
||||
st_sensors_irq_handler,
|
||||
st_sensors_irq_thread,
|
||||
|
@ -242,7 +242,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data)
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
if (events & AD5421_FAULT_UNDER_CURRENT) {
|
||||
@ -251,7 +251,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data)
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
if (events & AD5421_FAULT_TEMP_OVER_140) {
|
||||
@ -260,7 +260,7 @@ static irqreturn_t ad5421_fault_handler(int irq, void *data)
|
||||
0,
|
||||
IIO_EV_TYPE_MAG,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
old_fault = fault;
|
||||
|
@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private)
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns((struct iio_dev *)private));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -85,7 +85,8 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
|
||||
}
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
kfree(data);
|
||||
|
||||
|
@ -158,7 +158,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct iio_dummy_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->event_timestamp = iio_get_time_ns();
|
||||
st->event_timestamp = iio_get_time_ns(indio_dev);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@
|
||||
#define BMG160_REG_PMU_BW 0x10
|
||||
#define BMG160_NO_FILTER 0
|
||||
#define BMG160_DEF_BW 100
|
||||
#define BMG160_REG_PMU_BW_RES BIT(7)
|
||||
|
||||
#define BMG160_REG_INT_MAP_0 0x17
|
||||
#define BMG160_INT_MAP_0_BIT_ANY BIT(1)
|
||||
@ -100,7 +101,6 @@ struct bmg160_data {
|
||||
struct iio_trigger *motion_trig;
|
||||
struct mutex mutex;
|
||||
s16 buffer[8];
|
||||
u8 bw_bits;
|
||||
u32 dps_range;
|
||||
int ev_enable_state;
|
||||
int slope_thres;
|
||||
@ -117,13 +117,16 @@ enum bmg160_axis {
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int val;
|
||||
int odr;
|
||||
int filter;
|
||||
int bw_bits;
|
||||
} bmg160_samp_freq_table[] = { {100, 0x07},
|
||||
{200, 0x06},
|
||||
{400, 0x03},
|
||||
{1000, 0x02},
|
||||
{2000, 0x01} };
|
||||
} bmg160_samp_freq_table[] = { {100, 32, 0x07},
|
||||
{200, 64, 0x06},
|
||||
{100, 12, 0x05},
|
||||
{200, 23, 0x04},
|
||||
{400, 47, 0x03},
|
||||
{1000, 116, 0x02},
|
||||
{2000, 230, 0x01} };
|
||||
|
||||
static const struct {
|
||||
int scale;
|
||||
@ -153,7 +156,7 @@ static int bmg160_convert_freq_to_bit(int val)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
|
||||
if (bmg160_samp_freq_table[i].val == val)
|
||||
if (bmg160_samp_freq_table[i].odr == val)
|
||||
return bmg160_samp_freq_table[i].bw_bits;
|
||||
}
|
||||
|
||||
@ -176,7 +179,53 @@ static int bmg160_set_bw(struct bmg160_data *data, int val)
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->bw_bits = bw_bits;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmg160_get_filter(struct bmg160_data *data, int *val)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
int i;
|
||||
unsigned int bw_bits;
|
||||
|
||||
ret = regmap_read(data->regmap, BMG160_REG_PMU_BW, &bw_bits);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error reading reg_pmu_bw\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Ignore the readonly reserved bit. */
|
||||
bw_bits &= ~BMG160_REG_PMU_BW_RES;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
|
||||
if (bmg160_samp_freq_table[i].bw_bits == bw_bits)
|
||||
break;
|
||||
}
|
||||
|
||||
*val = bmg160_samp_freq_table[i].filter;
|
||||
|
||||
return ret ? ret : IIO_VAL_INT;
|
||||
}
|
||||
|
||||
|
||||
static int bmg160_set_filter(struct bmg160_data *data, int val)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
|
||||
if (bmg160_samp_freq_table[i].filter == val)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = regmap_write(data->regmap, BMG160_REG_PMU_BW,
|
||||
bmg160_samp_freq_table[i].bw_bits);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error writing reg_pmu_bw\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -386,11 +435,23 @@ static int bmg160_setup_new_data_interrupt(struct bmg160_data *data,
|
||||
|
||||
static int bmg160_get_bw(struct bmg160_data *data, int *val)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int i;
|
||||
unsigned int bw_bits;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, BMG160_REG_PMU_BW, &bw_bits);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error reading reg_pmu_bw\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Ignore the readonly reserved bit. */
|
||||
bw_bits &= ~BMG160_REG_PMU_BW_RES;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) {
|
||||
if (bmg160_samp_freq_table[i].bw_bits == data->bw_bits) {
|
||||
*val = bmg160_samp_freq_table[i].val;
|
||||
if (bmg160_samp_freq_table[i].bw_bits == bw_bits) {
|
||||
*val = bmg160_samp_freq_table[i].odr;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
}
|
||||
@ -507,6 +568,8 @@ static int bmg160_read_raw(struct iio_dev *indio_dev,
|
||||
return IIO_VAL_INT;
|
||||
} else
|
||||
return -EINVAL;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
return bmg160_get_filter(data, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
switch (chan->type) {
|
||||
@ -571,6 +634,26 @@ static int bmg160_write_raw(struct iio_dev *indio_dev,
|
||||
ret = bmg160_set_power_state(data, false);
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
if (val2)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = bmg160_set_power_state(data, true);
|
||||
if (ret < 0) {
|
||||
bmg160_set_power_state(data, false);
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
ret = bmg160_set_filter(data, val);
|
||||
if (ret < 0) {
|
||||
bmg160_set_power_state(data, false);
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
ret = bmg160_set_power_state(data, false);
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val)
|
||||
return -EINVAL;
|
||||
@ -728,7 +811,8 @@ static const struct iio_event_spec bmg160_event = {
|
||||
.channel2 = IIO_MOD_##_axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.scan_index = AXIS_##_axis, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
@ -885,25 +969,25 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
|
||||
|
||||
if (val & BMG160_ANY_MOTION_BIT_X)
|
||||
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
|
||||
0,
|
||||
IIO_MOD_X,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
iio_get_time_ns());
|
||||
0,
|
||||
IIO_MOD_X,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
iio_get_time_ns(indio_dev));
|
||||
if (val & BMG160_ANY_MOTION_BIT_Y)
|
||||
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
|
||||
0,
|
||||
IIO_MOD_Y,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
iio_get_time_ns());
|
||||
0,
|
||||
IIO_MOD_Y,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
iio_get_time_ns(indio_dev));
|
||||
if (val & BMG160_ANY_MOTION_BIT_Z)
|
||||
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
|
||||
0,
|
||||
IIO_MOD_Z,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
iio_get_time_ns());
|
||||
0,
|
||||
IIO_MOD_Z,
|
||||
IIO_EV_TYPE_ROC,
|
||||
dir),
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
ack_intr_status:
|
||||
if (!data->dready_trigger_on) {
|
||||
|
@ -79,4 +79,7 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev);
|
||||
void iio_device_wakeup_eventset(struct iio_dev *indio_dev);
|
||||
int iio_event_getfd(struct iio_dev *indio_dev);
|
||||
|
||||
struct iio_event_interface;
|
||||
bool iio_event_enabled(const struct iio_event_interface *ev_int);
|
||||
|
||||
#endif
|
||||
|
@ -411,7 +411,8 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
|
||||
buf[j++] = sample;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -13,8 +13,8 @@ config INV_MPU6050_I2C
|
||||
select INV_MPU6050_IIO
|
||||
select REGMAP_I2C
|
||||
help
|
||||
This driver supports the Invensense MPU6050/6500/9150 motion tracking
|
||||
devices over I2C.
|
||||
This driver supports the Invensense MPU6050/6500/9150 and ICM20608
|
||||
motion tracking devices over I2C.
|
||||
This driver can be built as a module. The module will be called
|
||||
inv-mpu6050-i2c.
|
||||
|
||||
@ -24,7 +24,7 @@ config INV_MPU6050_SPI
|
||||
select INV_MPU6050_IIO
|
||||
select REGMAP_SPI
|
||||
help
|
||||
This driver supports the Invensense MPU6000/6500/9150 motion tracking
|
||||
devices over SPI.
|
||||
This driver supports the Invensense MPU6050/6500/9150 and ICM20608
|
||||
motion tracking devices over SPI.
|
||||
This driver can be built as a module. The module will be called
|
||||
inv-mpu6050-spi.
|
||||
|
@ -113,6 +113,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
||||
.reg = ®_set_6050,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20608_WHOAMI_VALUE,
|
||||
.name = "ICM20608",
|
||||
.reg = ®_set_6500,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
};
|
||||
|
||||
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
|
||||
|
@ -170,6 +170,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
|
||||
{"mpu6050", INV_MPU6050},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{"mpu9150", INV_MPU9150},
|
||||
{"icm20608", INV_ICM20608},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,7 @@ enum inv_devices {
|
||||
INV_MPU6500,
|
||||
INV_MPU6000,
|
||||
INV_MPU9150,
|
||||
INV_ICM20608,
|
||||
INV_NUM_PARTS
|
||||
};
|
||||
|
||||
@ -225,6 +226,7 @@ struct inv_mpu6050_state {
|
||||
#define INV_MPU6050_WHOAMI_VALUE 0x68
|
||||
#define INV_MPU6500_WHOAMI_VALUE 0x70
|
||||
#define INV_MPU9150_WHOAMI_VALUE 0x68
|
||||
#define INV_ICM20608_WHOAMI_VALUE 0xAF
|
||||
|
||||
/* scan element definition */
|
||||
enum inv_mpu6050_scan {
|
||||
|
@ -107,7 +107,7 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
|
||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||
s64 timestamp;
|
||||
|
||||
timestamp = iio_get_time_ns();
|
||||
timestamp = iio_get_time_ns(indio_dev);
|
||||
kfifo_in_spinlocked(&st->timestamps, ×tamp, 1,
|
||||
&st->time_stamp_lock);
|
||||
|
||||
|
@ -82,6 +82,7 @@ static const struct spi_device_id inv_mpu_id[] = {
|
||||
{"mpu6000", INV_MPU6000},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{"mpu9150", INV_MPU9150},
|
||||
{"icm20608", INV_ICM20608},
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -178,6 +178,86 @@ ssize_t iio_read_const_attr(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(iio_read_const_attr);
|
||||
|
||||
static int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
|
||||
{
|
||||
int ret;
|
||||
const struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
|
||||
ret = mutex_lock_interruptible(&indio_dev->mlock);
|
||||
if (ret)
|
||||
return ret;
|
||||
if ((ev_int && iio_event_enabled(ev_int)) ||
|
||||
iio_buffer_enabled(indio_dev)) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EBUSY;
|
||||
}
|
||||
indio_dev->clock_id = clock_id;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_get_time_ns() - utility function to get a time stamp for events etc
|
||||
* @indio_dev: device
|
||||
*/
|
||||
s64 iio_get_time_ns(const struct iio_dev *indio_dev)
|
||||
{
|
||||
struct timespec tp;
|
||||
|
||||
switch (iio_device_get_clock(indio_dev)) {
|
||||
case CLOCK_REALTIME:
|
||||
ktime_get_real_ts(&tp);
|
||||
break;
|
||||
case CLOCK_MONOTONIC:
|
||||
ktime_get_ts(&tp);
|
||||
break;
|
||||
case CLOCK_MONOTONIC_RAW:
|
||||
getrawmonotonic(&tp);
|
||||
break;
|
||||
case CLOCK_REALTIME_COARSE:
|
||||
tp = current_kernel_time();
|
||||
break;
|
||||
case CLOCK_MONOTONIC_COARSE:
|
||||
tp = get_monotonic_coarse();
|
||||
break;
|
||||
case CLOCK_BOOTTIME:
|
||||
get_monotonic_boottime(&tp);
|
||||
break;
|
||||
case CLOCK_TAI:
|
||||
timekeeping_clocktai(&tp);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return timespec_to_ns(&tp);
|
||||
}
|
||||
EXPORT_SYMBOL(iio_get_time_ns);
|
||||
|
||||
/**
|
||||
* iio_get_time_res() - utility function to get time stamp clock resolution in
|
||||
* nano seconds.
|
||||
* @indio_dev: device
|
||||
*/
|
||||
unsigned int iio_get_time_res(const struct iio_dev *indio_dev)
|
||||
{
|
||||
switch (iio_device_get_clock(indio_dev)) {
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_MONOTONIC_RAW:
|
||||
case CLOCK_BOOTTIME:
|
||||
case CLOCK_TAI:
|
||||
return hrtimer_resolution;
|
||||
case CLOCK_REALTIME_COARSE:
|
||||
case CLOCK_MONOTONIC_COARSE:
|
||||
return LOW_RES_NSEC;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iio_get_time_res);
|
||||
|
||||
static int __init iio_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -990,11 +1070,91 @@ static ssize_t iio_show_dev_name(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
|
||||
|
||||
static ssize_t iio_show_timestamp_clock(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
const struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
const clockid_t clk = iio_device_get_clock(indio_dev);
|
||||
const char *name;
|
||||
ssize_t sz;
|
||||
|
||||
switch (clk) {
|
||||
case CLOCK_REALTIME:
|
||||
name = "realtime\n";
|
||||
sz = sizeof("realtime\n");
|
||||
break;
|
||||
case CLOCK_MONOTONIC:
|
||||
name = "monotonic\n";
|
||||
sz = sizeof("monotonic\n");
|
||||
break;
|
||||
case CLOCK_MONOTONIC_RAW:
|
||||
name = "monotonic_raw\n";
|
||||
sz = sizeof("monotonic_raw\n");
|
||||
break;
|
||||
case CLOCK_REALTIME_COARSE:
|
||||
name = "realtime_coarse\n";
|
||||
sz = sizeof("realtime_coarse\n");
|
||||
break;
|
||||
case CLOCK_MONOTONIC_COARSE:
|
||||
name = "monotonic_coarse\n";
|
||||
sz = sizeof("monotonic_coarse\n");
|
||||
break;
|
||||
case CLOCK_BOOTTIME:
|
||||
name = "boottime\n";
|
||||
sz = sizeof("boottime\n");
|
||||
break;
|
||||
case CLOCK_TAI:
|
||||
name = "tai\n";
|
||||
sz = sizeof("tai\n");
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
memcpy(buf, name, sz);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static ssize_t iio_store_timestamp_clock(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
clockid_t clk;
|
||||
int ret;
|
||||
|
||||
if (sysfs_streq(buf, "realtime"))
|
||||
clk = CLOCK_REALTIME;
|
||||
else if (sysfs_streq(buf, "monotonic"))
|
||||
clk = CLOCK_MONOTONIC;
|
||||
else if (sysfs_streq(buf, "monotonic_raw"))
|
||||
clk = CLOCK_MONOTONIC_RAW;
|
||||
else if (sysfs_streq(buf, "realtime_coarse"))
|
||||
clk = CLOCK_REALTIME_COARSE;
|
||||
else if (sysfs_streq(buf, "monotonic_coarse"))
|
||||
clk = CLOCK_MONOTONIC_COARSE;
|
||||
else if (sysfs_streq(buf, "boottime"))
|
||||
clk = CLOCK_BOOTTIME;
|
||||
else if (sysfs_streq(buf, "tai"))
|
||||
clk = CLOCK_TAI;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_device_set_clock(dev_to_iio_dev(dev), clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR,
|
||||
iio_show_timestamp_clock, iio_store_timestamp_clock);
|
||||
|
||||
static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
||||
{
|
||||
int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
|
||||
struct iio_dev_attr *p;
|
||||
struct attribute **attr;
|
||||
struct attribute **attr, *clk = NULL;
|
||||
|
||||
/* First count elements in any existing group */
|
||||
if (indio_dev->info->attrs) {
|
||||
@ -1009,16 +1169,25 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
||||
*/
|
||||
if (indio_dev->channels)
|
||||
for (i = 0; i < indio_dev->num_channels; i++) {
|
||||
ret = iio_device_add_channel_sysfs(indio_dev,
|
||||
&indio_dev
|
||||
->channels[i]);
|
||||
const struct iio_chan_spec *chan =
|
||||
&indio_dev->channels[i];
|
||||
|
||||
if (chan->type == IIO_TIMESTAMP)
|
||||
clk = &dev_attr_current_timestamp_clock.attr;
|
||||
|
||||
ret = iio_device_add_channel_sysfs(indio_dev, chan);
|
||||
if (ret < 0)
|
||||
goto error_clear_attrs;
|
||||
attrcount += ret;
|
||||
}
|
||||
|
||||
if (indio_dev->event_interface)
|
||||
clk = &dev_attr_current_timestamp_clock.attr;
|
||||
|
||||
if (indio_dev->name)
|
||||
attrcount++;
|
||||
if (clk)
|
||||
attrcount++;
|
||||
|
||||
indio_dev->chan_attr_group.attrs = kcalloc(attrcount + 1,
|
||||
sizeof(indio_dev->chan_attr_group.attrs[0]),
|
||||
@ -1039,6 +1208,8 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
||||
indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr;
|
||||
if (indio_dev->name)
|
||||
indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr;
|
||||
if (clk)
|
||||
indio_dev->chan_attr_group.attrs[attrn++] = clk;
|
||||
|
||||
indio_dev->groups[indio_dev->groupcounter++] =
|
||||
&indio_dev->chan_attr_group;
|
||||
|
@ -44,6 +44,11 @@ struct iio_event_interface {
|
||||
struct mutex read_lock;
|
||||
};
|
||||
|
||||
bool iio_event_enabled(const struct iio_event_interface *ev_int)
|
||||
{
|
||||
return !!test_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_push_event() - try to add event to the list for userspace reading
|
||||
* @indio_dev: IIO device structure
|
||||
@ -60,7 +65,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
|
||||
int copied;
|
||||
|
||||
/* Does anyone care? */
|
||||
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||
if (iio_event_enabled(ev_int)) {
|
||||
|
||||
ev.id = ev_code;
|
||||
ev.timestamp = timestamp;
|
||||
@ -180,8 +185,14 @@ int iio_event_getfd(struct iio_dev *indio_dev)
|
||||
if (ev_int == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags))
|
||||
return -EBUSY;
|
||||
fd = mutex_lock_interruptible(&indio_dev->mlock);
|
||||
if (fd)
|
||||
return fd;
|
||||
|
||||
if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||
fd = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
iio_device_get(indio_dev);
|
||||
|
||||
@ -194,6 +205,8 @@ int iio_event_getfd(struct iio_dev *indio_dev)
|
||||
kfifo_reset_out(&ev_int->det_events);
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
|
||||
irqreturn_t iio_pollfunc_store_time(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
pf->timestamp = iio_get_time_ns();
|
||||
pf->timestamp = iio_get_time_ns(pf->indio_dev);
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_pollfunc_store_time);
|
||||
|
@ -118,7 +118,7 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
|
||||
struct iio_dev *indio_dev = acpi_driver_data(device);
|
||||
struct acpi_als *als = iio_priv(indio_dev);
|
||||
s32 *buffer = als->evt_buffer;
|
||||
s64 time_ns = iio_get_time_ns();
|
||||
s64 time_ns = iio_get_time_ns(indio_dev);
|
||||
s32 val;
|
||||
int ret;
|
||||
|
||||
|
@ -118,7 +118,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct adjd_s311_data *data = iio_priv(indio_dev);
|
||||
s64 time_ns = iio_get_time_ns();
|
||||
s64 time_ns = iio_get_time_ns(indio_dev);
|
||||
int i, j = 0;
|
||||
|
||||
int ret = adjd_s311_req_data(indio_dev);
|
||||
|
@ -396,7 +396,7 @@ static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
|
||||
IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(dev_info));
|
||||
|
||||
apds9300_clear_intr(data);
|
||||
|
||||
|
@ -807,7 +807,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
|
||||
IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1);
|
||||
}
|
||||
|
||||
@ -816,7 +816,7 @@ static irqreturn_t apds9960_interrupt_handler(int irq, void *private)
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1);
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ static irqreturn_t cm36651_irq_handler(int irq, void *data)
|
||||
CM36651_CMD_READ_RAW_PROXIMITY,
|
||||
IIO_EV_TYPE_THRESH, ev_dir);
|
||||
|
||||
iio_push_event(indio_dev, ev_code, iio_get_time_ns());
|
||||
iio_push_event(indio_dev, ev_code, iio_get_time_ns(indio_dev));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -851,7 +851,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)
|
||||
GP2AP020A00F_SCAN_MODE_PROXIMITY,
|
||||
IIO_EV_TYPE_ROC,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
} else {
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(
|
||||
@ -859,7 +859,7 @@ static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)
|
||||
GP2AP020A00F_SCAN_MODE_PROXIMITY,
|
||||
IIO_EV_TYPE_ROC,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
}
|
||||
|
||||
@ -925,7 +925,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
|
||||
IIO_MOD_LIGHT_CLEAR,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
|
||||
if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) {
|
||||
@ -939,7 +939,7 @@ static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)
|
||||
IIO_MOD_LIGHT_CLEAR,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,9 @@
|
||||
#define ISL29125_MODE_B 0x3
|
||||
#define ISL29125_MODE_RGB 0x5
|
||||
|
||||
#define ISL29125_SENSING_RANGE_0 5722 /* 375 lux full range */
|
||||
#define ISL29125_SENSING_RANGE_1 152590 /* 10k lux full range */
|
||||
|
||||
#define ISL29125_MODE_RANGE BIT(3)
|
||||
|
||||
#define ISL29125_STATUS_CONV BIT(1)
|
||||
@ -139,9 +142,9 @@ static int isl29125_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
if (data->conf1 & ISL29125_MODE_RANGE)
|
||||
*val2 = 152590; /* 10k lux full range */
|
||||
*val2 = ISL29125_SENSING_RANGE_1; /*10k lux full range*/
|
||||
else
|
||||
*val2 = 5722; /* 375 lux full range */
|
||||
*val2 = ISL29125_SENSING_RANGE_0; /*375 lux full range*/
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
return -EINVAL;
|
||||
@ -157,9 +160,9 @@ static int isl29125_write_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
if (val2 == 152590)
|
||||
if (val2 == ISL29125_SENSING_RANGE_1)
|
||||
data->conf1 |= ISL29125_MODE_RANGE;
|
||||
else if (val2 == 5722)
|
||||
else if (val2 == ISL29125_SENSING_RANGE_0)
|
||||
data->conf1 &= ~ISL29125_MODE_RANGE;
|
||||
else
|
||||
return -EINVAL;
|
||||
@ -188,7 +191,7 @@ static irqreturn_t isl29125_trigger_handler(int irq, void *p)
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -267,7 +267,7 @@ static irqreturn_t lm3533_als_isr(int irq, void *dev_id)
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -1256,7 +1256,8 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p)
|
||||
buf[j++] = psdata & LTR501_PS_DATA_MASK;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -1282,14 +1283,14 @@ static irqreturn_t ltr501_interrupt_handler(int irq, void *private)
|
||||
IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
if (status & LTR501_STATUS_PS_INTR)
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -511,7 +511,8 @@ static irqreturn_t max44000_trigger_handler(int irq, void *p)
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
|
@ -713,13 +713,13 @@ static irqreturn_t opt3001_irq(int irq, void *_iio)
|
||||
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(iio));
|
||||
if (ret & OPT3001_CONFIGURATION_FL)
|
||||
iio_push_event(iio,
|
||||
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(iio));
|
||||
} else if (ret & OPT3001_CONFIGURATION_CRF) {
|
||||
ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
|
||||
if (ret < 0) {
|
||||
|
@ -528,7 +528,7 @@ static irqreturn_t stk3310_irq_handler(int irq, void *private)
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct stk3310_data *data = iio_priv(indio_dev);
|
||||
|
||||
data->timestamp = iio_get_time_ns();
|
||||
data->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ static irqreturn_t tcs3414_trigger_handler(int irq, void *p)
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -202,7 +202,7 @@ static irqreturn_t tcs3472_trigger_handler(int irq, void *p)
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -630,7 +630,7 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private)
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(dev_info));
|
||||
|
||||
/* clear the interrupt and push the event */
|
||||
i2c_smbus_write_byte(chip->client, TSL2563_CMD | TSL2563_CLEARINT);
|
||||
|
@ -833,7 +833,7 @@ static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)
|
||||
dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
|
||||
ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir);
|
||||
|
||||
iio_push_event(indio_dev, ev, iio_get_time_ns());
|
||||
iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0,
|
||||
ret & ~US5182D_CFG0_PX_IRQ);
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
@ -379,37 +380,40 @@ struct ak8975_data {
|
||||
u8 cntl_cache;
|
||||
struct iio_mount_matrix orientation;
|
||||
struct regulator *vdd;
|
||||
struct regulator *vid;
|
||||
};
|
||||
|
||||
/* Enable attached power regulator if any. */
|
||||
static int ak8975_power_on(struct i2c_client *client)
|
||||
static int ak8975_power_on(const struct ak8975_data *data)
|
||||
{
|
||||
const struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
data->vdd = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR_OR_NULL(data->vdd)) {
|
||||
ret = PTR_ERR(data->vdd);
|
||||
if (ret == -ENODEV)
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = regulator_enable(data->vdd);
|
||||
ret = regulator_enable(data->vdd);
|
||||
if (ret) {
|
||||
dev_warn(&data->client->dev,
|
||||
"Failed to enable specified Vdd supply\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(&client->dev, "failed to enable Vdd supply: %d\n", ret);
|
||||
return ret;
|
||||
ret = regulator_enable(data->vid);
|
||||
if (ret) {
|
||||
dev_warn(&data->client->dev,
|
||||
"Failed to enable specified Vid supply\n");
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* According to the datasheet the power supply rise time i 200us
|
||||
* and the minimum wait time before mode setting is 100us, in
|
||||
* total 300 us. Add some margin and say minimum 500us here.
|
||||
*/
|
||||
usleep_range(500, 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disable attached power regulator if any. */
|
||||
static void ak8975_power_off(const struct i2c_client *client)
|
||||
static void ak8975_power_off(const struct ak8975_data *data)
|
||||
{
|
||||
const struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
const struct ak8975_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(data->vdd))
|
||||
regulator_disable(data->vdd);
|
||||
regulator_disable(data->vid);
|
||||
regulator_disable(data->vdd);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -689,6 +693,8 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
|
||||
u16 buff;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(&data->client->dev);
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ret = ak8975_start_read_axis(data, client);
|
||||
@ -703,6 +709,9 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
pm_runtime_mark_last_busy(&data->client->dev);
|
||||
pm_runtime_put_autosuspend(&data->client->dev);
|
||||
|
||||
/* Swap bytes and convert to valid range. */
|
||||
buff = le16_to_cpu(buff);
|
||||
*val = clamp_t(s16, buff, -def->range, def->range);
|
||||
@ -829,7 +838,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev)
|
||||
buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range);
|
||||
buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buff, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buff,
|
||||
iio_get_time_ns(indio_dev));
|
||||
return;
|
||||
|
||||
unlock:
|
||||
@ -923,7 +933,15 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
|
||||
data->def = &ak_def_array[chipset];
|
||||
|
||||
err = ak8975_power_on(client);
|
||||
/* Fetch the regulators */
|
||||
data->vdd = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR(data->vdd))
|
||||
return PTR_ERR(data->vdd);
|
||||
data->vid = devm_regulator_get(&client->dev, "vid");
|
||||
if (IS_ERR(data->vid))
|
||||
return PTR_ERR(data->vid);
|
||||
|
||||
err = ak8975_power_on(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -963,26 +981,93 @@ static int ak8975_probe(struct i2c_client *client,
|
||||
goto cleanup_buffer;
|
||||
}
|
||||
|
||||
/* Enable runtime PM */
|
||||
pm_runtime_get_noresume(&client->dev);
|
||||
pm_runtime_set_active(&client->dev);
|
||||
pm_runtime_enable(&client->dev);
|
||||
/*
|
||||
* The device comes online in 500us, so add two orders of magnitude
|
||||
* of delay before autosuspending: 50 ms.
|
||||
*/
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, 50);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
pm_runtime_put(&client->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
power_off:
|
||||
ak8975_power_off(client);
|
||||
ak8975_power_off(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ak8975_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
|
||||
pm_runtime_get_sync(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
pm_runtime_disable(&client->dev);
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
ak8975_power_off(client);
|
||||
ak8975_set_mode(data, POWER_DOWN);
|
||||
ak8975_power_off(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ak8975_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* Set the device in power down if it wasn't already */
|
||||
ret = ak8975_set_mode(data, POWER_DOWN);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Error in setting power-down mode\n");
|
||||
return ret;
|
||||
}
|
||||
/* Next cut the regulators */
|
||||
ak8975_power_off(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak8975_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* Take up the regulators */
|
||||
ak8975_power_on(data);
|
||||
/*
|
||||
* We come up in powered down mode, the reading routines will
|
||||
* put us in the mode to read values later.
|
||||
*/
|
||||
ret = ak8975_set_mode(data, POWER_DOWN);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Error in setting power-down mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops ak8975_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(ak8975_runtime_suspend,
|
||||
ak8975_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct i2c_device_id ak8975_id[] = {
|
||||
{"ak8975", AK8975},
|
||||
{"ak8963", AK8963},
|
||||
@ -1010,6 +1095,7 @@ MODULE_DEVICE_TABLE(of, ak8975_of_match);
|
||||
static struct i2c_driver ak8975_driver = {
|
||||
.driver = {
|
||||
.name = "ak8975",
|
||||
.pm = &ak8975_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(ak8975_of_match),
|
||||
.acpi_match_table = ACPI_PTR(ak_acpi_match),
|
||||
},
|
||||
|
@ -451,7 +451,7 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -261,7 +261,7 @@ static irqreturn_t mag3110_trigger_handler(int irq, void *p)
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -10,7 +10,7 @@ config DS1803
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the Maxim Integrated DS1803
|
||||
digital potentiomenter chip.
|
||||
digital potentiometer chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ds1803.
|
||||
@ -39,7 +39,7 @@ config MCP4131
|
||||
MCP4241, MCP4242,
|
||||
MCP4251, MCP4252,
|
||||
MCP4261, MCP4262,
|
||||
digital potentiomenter chips.
|
||||
digital potentiometer chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcp4131.
|
||||
@ -49,9 +49,11 @@ config MCP4531
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the Microchip
|
||||
MCP4531, MCP4532, MCP4551, MCP4552,
|
||||
MCP4631, MCP4632, MCP4651, MCP4652
|
||||
digital potentiomenter chips.
|
||||
MCP4531, MCP4532, MCP4541, MCP4542,
|
||||
MCP4551, MCP4552, MCP4561, MCP4562,
|
||||
MCP4631, MCP4632, MCP4641, MCP4642,
|
||||
MCP4651, MCP4652, MCP4661, MCP4662
|
||||
digital potentiometer chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcp4531.
|
||||
|
@ -8,12 +8,20 @@
|
||||
* DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
|
||||
* mcp4531 1 129 5, 10, 50, 100 010111x
|
||||
* mcp4532 1 129 5, 10, 50, 100 01011xx
|
||||
* mcp4541 1 129 5, 10, 50, 100 010111x
|
||||
* mcp4542 1 129 5, 10, 50, 100 01011xx
|
||||
* mcp4551 1 257 5, 10, 50, 100 010111x
|
||||
* mcp4552 1 257 5, 10, 50, 100 01011xx
|
||||
* mcp4561 1 257 5, 10, 50, 100 010111x
|
||||
* mcp4562 1 257 5, 10, 50, 100 01011xx
|
||||
* mcp4631 2 129 5, 10, 50, 100 0101xxx
|
||||
* mcp4632 2 129 5, 10, 50, 100 01011xx
|
||||
* mcp4641 2 129 5, 10, 50, 100 0101xxx
|
||||
* mcp4642 2 129 5, 10, 50, 100 01011xx
|
||||
* mcp4651 2 257 5, 10, 50, 100 0101xxx
|
||||
* mcp4652 2 257 5, 10, 50, 100 01011xx
|
||||
* mcp4661 2 257 5, 10, 50, 100 0101xxx
|
||||
* mcp4662 2 257 5, 10, 50, 100 01011xx
|
||||
*
|
||||
* 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
|
||||
@ -23,6 +31,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
@ -37,18 +47,34 @@ enum mcp4531_type {
|
||||
MCP453x_103,
|
||||
MCP453x_503,
|
||||
MCP453x_104,
|
||||
MCP454x_502,
|
||||
MCP454x_103,
|
||||
MCP454x_503,
|
||||
MCP454x_104,
|
||||
MCP455x_502,
|
||||
MCP455x_103,
|
||||
MCP455x_503,
|
||||
MCP455x_104,
|
||||
MCP456x_502,
|
||||
MCP456x_103,
|
||||
MCP456x_503,
|
||||
MCP456x_104,
|
||||
MCP463x_502,
|
||||
MCP463x_103,
|
||||
MCP463x_503,
|
||||
MCP463x_104,
|
||||
MCP464x_502,
|
||||
MCP464x_103,
|
||||
MCP464x_503,
|
||||
MCP464x_104,
|
||||
MCP465x_502,
|
||||
MCP465x_103,
|
||||
MCP465x_503,
|
||||
MCP465x_104,
|
||||
MCP466x_502,
|
||||
MCP466x_103,
|
||||
MCP466x_503,
|
||||
MCP466x_104,
|
||||
};
|
||||
|
||||
static const struct mcp4531_cfg mcp4531_cfg[] = {
|
||||
@ -56,18 +82,34 @@ static const struct mcp4531_cfg mcp4531_cfg[] = {
|
||||
[MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
|
||||
[MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
|
||||
[MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
|
||||
[MCP454x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
|
||||
[MCP454x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
|
||||
[MCP454x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
|
||||
[MCP454x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
|
||||
[MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
|
||||
[MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
|
||||
[MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
|
||||
[MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
|
||||
[MCP456x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
|
||||
[MCP456x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
|
||||
[MCP456x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
|
||||
[MCP456x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
|
||||
[MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
|
||||
[MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
|
||||
[MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
|
||||
[MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
|
||||
[MCP464x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
|
||||
[MCP464x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
|
||||
[MCP464x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
|
||||
[MCP464x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
|
||||
[MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
|
||||
[MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
|
||||
[MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
|
||||
[MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
|
||||
[MCP466x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
|
||||
[MCP466x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
|
||||
[MCP466x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
|
||||
[MCP466x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
|
||||
};
|
||||
|
||||
#define MCP4531_WRITE (0 << 2)
|
||||
@ -148,12 +190,89 @@ static const struct iio_info mcp4531_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
#define MCP4531_COMPATIBLE(of_compatible, cfg) { \
|
||||
.compatible = of_compatible, \
|
||||
.data = &mcp4531_cfg[cfg], \
|
||||
}
|
||||
|
||||
static const struct of_device_id mcp4531_of_match[] = {
|
||||
MCP4531_COMPATIBLE("microchip,mcp4531-502", MCP453x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4531-103", MCP453x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4531-503", MCP453x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4531-104", MCP453x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4532-502", MCP453x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4532-103", MCP453x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4532-503", MCP453x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4532-104", MCP453x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4541-502", MCP454x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4541-103", MCP454x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4541-503", MCP454x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4541-104", MCP454x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4542-502", MCP454x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4542-103", MCP454x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4542-503", MCP454x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4542-104", MCP454x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4551-502", MCP455x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4551-103", MCP455x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4551-503", MCP455x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4551-104", MCP455x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4552-502", MCP455x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4552-103", MCP455x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4552-503", MCP455x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4552-104", MCP455x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4561-502", MCP456x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4561-103", MCP456x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4561-503", MCP456x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4561-104", MCP456x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4562-502", MCP456x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4562-103", MCP456x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4562-503", MCP456x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4562-104", MCP456x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4631-502", MCP463x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4631-103", MCP463x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4631-503", MCP463x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4631-104", MCP463x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4632-502", MCP463x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4632-103", MCP463x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4632-503", MCP463x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4632-104", MCP463x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4641-502", MCP464x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4641-103", MCP464x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4641-503", MCP464x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4641-104", MCP464x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4642-502", MCP464x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4642-103", MCP464x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4642-503", MCP464x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4642-104", MCP464x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4651-502", MCP465x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4651-103", MCP465x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4651-503", MCP465x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4651-104", MCP465x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4652-502", MCP465x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4652-103", MCP465x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4652-503", MCP465x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4652-104", MCP465x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4661-502", MCP466x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4661-103", MCP466x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4661-503", MCP466x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4661-104", MCP466x_104),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4662-502", MCP466x_502),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4662-103", MCP466x_103),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4662-503", MCP466x_503),
|
||||
MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
#endif
|
||||
|
||||
static int mcp4531_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct mcp4531_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||
@ -167,7 +286,12 @@ static int mcp4531_probe(struct i2c_client *client,
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->cfg = &mcp4531_cfg[id->driver_data];
|
||||
|
||||
match = of_match_device(of_match_ptr(mcp4531_of_match), dev);
|
||||
if (match)
|
||||
data->cfg = of_device_get_match_data(dev);
|
||||
else
|
||||
data->cfg = &mcp4531_cfg[id->driver_data];
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &mcp4531_info;
|
||||
@ -187,6 +311,14 @@ static const struct i2c_device_id mcp4531_id[] = {
|
||||
{ "mcp4532-103", MCP453x_103 },
|
||||
{ "mcp4532-503", MCP453x_503 },
|
||||
{ "mcp4532-104", MCP453x_104 },
|
||||
{ "mcp4541-502", MCP454x_502 },
|
||||
{ "mcp4541-103", MCP454x_103 },
|
||||
{ "mcp4541-503", MCP454x_503 },
|
||||
{ "mcp4541-104", MCP454x_104 },
|
||||
{ "mcp4542-502", MCP454x_502 },
|
||||
{ "mcp4542-103", MCP454x_103 },
|
||||
{ "mcp4542-503", MCP454x_503 },
|
||||
{ "mcp4542-104", MCP454x_104 },
|
||||
{ "mcp4551-502", MCP455x_502 },
|
||||
{ "mcp4551-103", MCP455x_103 },
|
||||
{ "mcp4551-503", MCP455x_503 },
|
||||
@ -195,6 +327,14 @@ static const struct i2c_device_id mcp4531_id[] = {
|
||||
{ "mcp4552-103", MCP455x_103 },
|
||||
{ "mcp4552-503", MCP455x_503 },
|
||||
{ "mcp4552-104", MCP455x_104 },
|
||||
{ "mcp4561-502", MCP456x_502 },
|
||||
{ "mcp4561-103", MCP456x_103 },
|
||||
{ "mcp4561-503", MCP456x_503 },
|
||||
{ "mcp4561-104", MCP456x_104 },
|
||||
{ "mcp4562-502", MCP456x_502 },
|
||||
{ "mcp4562-103", MCP456x_103 },
|
||||
{ "mcp4562-503", MCP456x_503 },
|
||||
{ "mcp4562-104", MCP456x_104 },
|
||||
{ "mcp4631-502", MCP463x_502 },
|
||||
{ "mcp4631-103", MCP463x_103 },
|
||||
{ "mcp4631-503", MCP463x_503 },
|
||||
@ -203,6 +343,14 @@ static const struct i2c_device_id mcp4531_id[] = {
|
||||
{ "mcp4632-103", MCP463x_103 },
|
||||
{ "mcp4632-503", MCP463x_503 },
|
||||
{ "mcp4632-104", MCP463x_104 },
|
||||
{ "mcp4641-502", MCP464x_502 },
|
||||
{ "mcp4641-103", MCP464x_103 },
|
||||
{ "mcp4641-503", MCP464x_503 },
|
||||
{ "mcp4641-104", MCP464x_104 },
|
||||
{ "mcp4642-502", MCP464x_502 },
|
||||
{ "mcp4642-103", MCP464x_103 },
|
||||
{ "mcp4642-503", MCP464x_503 },
|
||||
{ "mcp4642-104", MCP464x_104 },
|
||||
{ "mcp4651-502", MCP465x_502 },
|
||||
{ "mcp4651-103", MCP465x_103 },
|
||||
{ "mcp4651-503", MCP465x_503 },
|
||||
@ -211,6 +359,14 @@ static const struct i2c_device_id mcp4531_id[] = {
|
||||
{ "mcp4652-103", MCP465x_103 },
|
||||
{ "mcp4652-503", MCP465x_503 },
|
||||
{ "mcp4652-104", MCP465x_104 },
|
||||
{ "mcp4661-502", MCP466x_502 },
|
||||
{ "mcp4661-103", MCP466x_103 },
|
||||
{ "mcp4661-503", MCP466x_503 },
|
||||
{ "mcp4661-104", MCP466x_104 },
|
||||
{ "mcp4662-502", MCP466x_502 },
|
||||
{ "mcp4662-103", MCP466x_103 },
|
||||
{ "mcp4662-503", MCP466x_503 },
|
||||
{ "mcp4662-104", MCP466x_104 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mcp4531_id);
|
||||
@ -218,6 +374,7 @@ MODULE_DEVICE_TABLE(i2c, mcp4531_id);
|
||||
static struct i2c_driver mcp4531_driver = {
|
||||
.driver = {
|
||||
.name = "mcp4531",
|
||||
.of_match_table = of_match_ptr(mcp4531_of_match),
|
||||
},
|
||||
.probe = mcp4531_probe,
|
||||
.id_table = mcp4531_id,
|
||||
|
@ -6,17 +6,33 @@
|
||||
menu "Pressure sensors"
|
||||
|
||||
config BMP280
|
||||
tristate "Bosch Sensortec BMP180 and BMP280 pressure sensor driver"
|
||||
depends on I2C
|
||||
tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver"
|
||||
depends on (I2C || SPI_MASTER)
|
||||
depends on !(BMP085_I2C=y || BMP085_I2C=m)
|
||||
select REGMAP_I2C
|
||||
depends on !(BMP085_SPI=y || BMP085_SPI=m)
|
||||
select REGMAP
|
||||
select BMP280_I2C if (I2C)
|
||||
select BMP280_SPI if (SPI_MASTER)
|
||||
help
|
||||
Say yes here to build support for Bosch Sensortec BMP180 and BMP280
|
||||
pressure and temperature sensors. Also supports the BE280 with
|
||||
an additional humidty sensor channel.
|
||||
an additional humidity sensor channel.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called bmp280.
|
||||
To compile this driver as a module, choose M here: the core module
|
||||
will be called bmp280 and you will also get bmp280-i2c for I2C
|
||||
and/or bmp280-spi for SPI support.
|
||||
|
||||
config BMP280_I2C
|
||||
tristate
|
||||
depends on BMP280
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
|
||||
config BMP280_SPI
|
||||
tristate
|
||||
depends on BMP280
|
||||
depends on SPI_MASTER
|
||||
select REGMAP
|
||||
|
||||
config HID_SENSOR_PRESS
|
||||
depends on HID_SENSOR_HUB
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_BMP280) += bmp280.o
|
||||
bmp280-objs := bmp280-core.o bmp280-regmap.o
|
||||
obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
|
||||
obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
|
||||
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
|
||||
obj-$(CONFIG_HP03) += hp03.o
|
||||
obj-$(CONFIG_MPL115) += mpl115.o
|
||||
|
@ -1,5 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
|
||||
* Copyright (c) 2012 Bosch Sensortec GmbH
|
||||
* Copyright (c) 2012 Unixphere AB
|
||||
* Copyright (c) 2014 Intel Corporation
|
||||
* Copyright (c) 2016 Linus Walleij <linus.walleij@linaro.org>
|
||||
*
|
||||
* Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor.
|
||||
*
|
||||
@ -15,113 +19,53 @@
|
||||
|
||||
#define pr_fmt(fmt) "bmp280: " fmt
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h> /* For irq_get_irq_data() */
|
||||
#include <linux/completion.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
/* BMP280 specific registers */
|
||||
#define BMP280_REG_HUMIDITY_LSB 0xFE
|
||||
#define BMP280_REG_HUMIDITY_MSB 0xFD
|
||||
#define BMP280_REG_TEMP_XLSB 0xFC
|
||||
#define BMP280_REG_TEMP_LSB 0xFB
|
||||
#define BMP280_REG_TEMP_MSB 0xFA
|
||||
#define BMP280_REG_PRESS_XLSB 0xF9
|
||||
#define BMP280_REG_PRESS_LSB 0xF8
|
||||
#define BMP280_REG_PRESS_MSB 0xF7
|
||||
#include "bmp280.h"
|
||||
|
||||
#define BMP280_REG_CONFIG 0xF5
|
||||
#define BMP280_REG_CTRL_MEAS 0xF4
|
||||
#define BMP280_REG_STATUS 0xF3
|
||||
#define BMP280_REG_CTRL_HUMIDITY 0xF2
|
||||
/*
|
||||
* These enums are used for indexing into the array of calibration
|
||||
* coefficients for BMP180.
|
||||
*/
|
||||
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
|
||||
|
||||
/* Due to non linear mapping, and data sizes we can't do a bulk read */
|
||||
#define BMP280_REG_COMP_H1 0xA1
|
||||
#define BMP280_REG_COMP_H2 0xE1
|
||||
#define BMP280_REG_COMP_H3 0xE3
|
||||
#define BMP280_REG_COMP_H4 0xE4
|
||||
#define BMP280_REG_COMP_H5 0xE5
|
||||
#define BMP280_REG_COMP_H6 0xE7
|
||||
|
||||
#define BMP280_REG_COMP_TEMP_START 0x88
|
||||
#define BMP280_COMP_TEMP_REG_COUNT 6
|
||||
|
||||
#define BMP280_REG_COMP_PRESS_START 0x8E
|
||||
#define BMP280_COMP_PRESS_REG_COUNT 18
|
||||
|
||||
#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2))
|
||||
#define BMP280_FILTER_OFF 0
|
||||
#define BMP280_FILTER_2X BIT(2)
|
||||
#define BMP280_FILTER_4X BIT(3)
|
||||
#define BMP280_FILTER_8X (BIT(3) | BIT(2))
|
||||
#define BMP280_FILTER_16X BIT(4)
|
||||
|
||||
#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0))
|
||||
#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0)
|
||||
#define BMP280_OSRS_HUMIDITY_SKIP 0
|
||||
#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1)
|
||||
#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2)
|
||||
#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3)
|
||||
#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4)
|
||||
#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5)
|
||||
|
||||
#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5))
|
||||
#define BMP280_OSRS_TEMP_SKIP 0
|
||||
#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5)
|
||||
#define BMP280_OSRS_TEMP_1X BMP280_OSRS_TEMP_X(1)
|
||||
#define BMP280_OSRS_TEMP_2X BMP280_OSRS_TEMP_X(2)
|
||||
#define BMP280_OSRS_TEMP_4X BMP280_OSRS_TEMP_X(3)
|
||||
#define BMP280_OSRS_TEMP_8X BMP280_OSRS_TEMP_X(4)
|
||||
#define BMP280_OSRS_TEMP_16X BMP280_OSRS_TEMP_X(5)
|
||||
|
||||
#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2))
|
||||
#define BMP280_OSRS_PRESS_SKIP 0
|
||||
#define BMP280_OSRS_PRESS_X(osrs_p) ((osrs_p) << 2)
|
||||
#define BMP280_OSRS_PRESS_1X BMP280_OSRS_PRESS_X(1)
|
||||
#define BMP280_OSRS_PRESS_2X BMP280_OSRS_PRESS_X(2)
|
||||
#define BMP280_OSRS_PRESS_4X BMP280_OSRS_PRESS_X(3)
|
||||
#define BMP280_OSRS_PRESS_8X BMP280_OSRS_PRESS_X(4)
|
||||
#define BMP280_OSRS_PRESS_16X BMP280_OSRS_PRESS_X(5)
|
||||
|
||||
#define BMP280_MODE_MASK (BIT(1) | BIT(0))
|
||||
#define BMP280_MODE_SLEEP 0
|
||||
#define BMP280_MODE_FORCED BIT(0)
|
||||
#define BMP280_MODE_NORMAL (BIT(1) | BIT(0))
|
||||
|
||||
/* BMP180 specific registers */
|
||||
#define BMP180_REG_OUT_XLSB 0xF8
|
||||
#define BMP180_REG_OUT_LSB 0xF7
|
||||
#define BMP180_REG_OUT_MSB 0xF6
|
||||
|
||||
#define BMP180_REG_CALIB_START 0xAA
|
||||
#define BMP180_REG_CALIB_COUNT 22
|
||||
|
||||
#define BMP180_MEAS_SCO BIT(5)
|
||||
#define BMP180_MEAS_TEMP (0x0E | BMP180_MEAS_SCO)
|
||||
#define BMP180_MEAS_PRESS_X(oss) ((oss) << 6 | 0x14 | BMP180_MEAS_SCO)
|
||||
#define BMP180_MEAS_PRESS_1X BMP180_MEAS_PRESS_X(0)
|
||||
#define BMP180_MEAS_PRESS_2X BMP180_MEAS_PRESS_X(1)
|
||||
#define BMP180_MEAS_PRESS_4X BMP180_MEAS_PRESS_X(2)
|
||||
#define BMP180_MEAS_PRESS_8X BMP180_MEAS_PRESS_X(3)
|
||||
|
||||
/* BMP180 and BMP280 common registers */
|
||||
#define BMP280_REG_CTRL_MEAS 0xF4
|
||||
#define BMP280_REG_RESET 0xE0
|
||||
#define BMP280_REG_ID 0xD0
|
||||
|
||||
#define BMP180_CHIP_ID 0x55
|
||||
#define BMP280_CHIP_ID 0x58
|
||||
#define BME280_CHIP_ID 0x60
|
||||
#define BMP280_SOFT_RESET_VAL 0xB6
|
||||
struct bmp180_calib {
|
||||
s16 AC1;
|
||||
s16 AC2;
|
||||
s16 AC3;
|
||||
u16 AC4;
|
||||
u16 AC5;
|
||||
u16 AC6;
|
||||
s16 B1;
|
||||
s16 B2;
|
||||
s16 MB;
|
||||
s16 MC;
|
||||
s16 MD;
|
||||
};
|
||||
|
||||
struct bmp280_data {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
struct completion done;
|
||||
bool use_eoc;
|
||||
const struct bmp280_chip_info *chip_info;
|
||||
struct bmp180_calib calib;
|
||||
struct regulator *vddd;
|
||||
struct regulator *vdda;
|
||||
unsigned int start_up_time; /* in milliseconds */
|
||||
|
||||
/* log of base 2 of oversampling rate */
|
||||
u8 oversampling_press;
|
||||
@ -136,8 +80,6 @@ struct bmp280_data {
|
||||
};
|
||||
|
||||
struct bmp280_chip_info {
|
||||
const struct regmap_config *regmap_config;
|
||||
|
||||
const int *oversampling_temp_avail;
|
||||
int num_oversampling_temp_avail;
|
||||
|
||||
@ -178,48 +120,6 @@ static const struct iio_chan_spec bmp280_channels[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_CONFIG:
|
||||
case BMP280_REG_CTRL_HUMIDITY:
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
case BMP280_REG_RESET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_HUMIDITY_LSB:
|
||||
case BMP280_REG_HUMIDITY_MSB:
|
||||
case BMP280_REG_TEMP_XLSB:
|
||||
case BMP280_REG_TEMP_LSB:
|
||||
case BMP280_REG_TEMP_MSB:
|
||||
case BMP280_REG_PRESS_XLSB:
|
||||
case BMP280_REG_PRESS_LSB:
|
||||
case BMP280_REG_PRESS_MSB:
|
||||
case BMP280_REG_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config bmp280_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = BMP280_REG_HUMIDITY_LSB,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.writeable_reg = bmp280_is_writeable_reg,
|
||||
.volatile_reg = bmp280_is_volatile_reg,
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns humidity in percent, resolution is 0.01 percent. Output value of
|
||||
* "47445" represents 47445/1024 = 46.333 %RH.
|
||||
@ -230,7 +130,7 @@ static const struct regmap_config bmp280_regmap_config = {
|
||||
static u32 bmp280_compensate_humidity(struct bmp280_data *data,
|
||||
s32 adc_humidity)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
struct device *dev = data->dev;
|
||||
unsigned int H1, H3, tmp;
|
||||
int H2, H4, H5, H6, ret, var;
|
||||
|
||||
@ -301,7 +201,7 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data,
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
|
||||
buf, BMP280_COMP_TEMP_REG_COUNT);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
dev_err(data->dev,
|
||||
"failed to read temperature calibration parameters\n");
|
||||
return ret;
|
||||
}
|
||||
@ -341,7 +241,7 @@ static u32 bmp280_compensate_press(struct bmp280_data *data,
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
|
||||
buf, BMP280_COMP_PRESS_REG_COUNT);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
dev_err(data->dev,
|
||||
"failed to read pressure calibration parameters\n");
|
||||
return ret;
|
||||
}
|
||||
@ -376,7 +276,7 @@ static int bmp280_read_temp(struct bmp280_data *data,
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
|
||||
(u8 *) &tmp, 3);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "failed to read temperature\n");
|
||||
dev_err(data->dev, "failed to read temperature\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -411,7 +311,7 @@ static int bmp280_read_press(struct bmp280_data *data,
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
|
||||
(u8 *) &tmp, 3);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "failed to read pressure\n");
|
||||
dev_err(data->dev, "failed to read pressure\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -439,7 +339,7 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB,
|
||||
(u8 *) &tmp, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "failed to read humidity\n");
|
||||
dev_err(data->dev, "failed to read humidity\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -459,6 +359,7 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
|
||||
int ret;
|
||||
struct bmp280_data *data = iio_priv(indio_dev);
|
||||
|
||||
pm_runtime_get_sync(data->dev);
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (mask) {
|
||||
@ -503,6 +404,8 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
pm_runtime_mark_last_busy(data->dev);
|
||||
pm_runtime_put_autosuspend(data->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -567,6 +470,7 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
pm_runtime_get_sync(data->dev);
|
||||
mutex_lock(&data->lock);
|
||||
switch (chan->type) {
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
@ -583,6 +487,8 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
pm_runtime_mark_last_busy(data->dev);
|
||||
pm_runtime_put_autosuspend(data->dev);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -657,7 +563,7 @@ static int bmp280_chip_config(struct bmp280_data *data)
|
||||
BMP280_MODE_MASK,
|
||||
osrs | BMP280_MODE_NORMAL);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
dev_err(data->dev,
|
||||
"failed to write ctrl_meas register\n");
|
||||
return ret;
|
||||
}
|
||||
@ -666,7 +572,7 @@ static int bmp280_chip_config(struct bmp280_data *data)
|
||||
BMP280_FILTER_MASK,
|
||||
BMP280_FILTER_4X);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
dev_err(data->dev,
|
||||
"failed to write config register\n");
|
||||
return ret;
|
||||
}
|
||||
@ -677,8 +583,6 @@ static int bmp280_chip_config(struct bmp280_data *data)
|
||||
static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
|
||||
|
||||
static const struct bmp280_chip_info bmp280_chip_info = {
|
||||
.regmap_config = &bmp280_regmap_config,
|
||||
|
||||
.oversampling_temp_avail = bmp280_oversampling_avail,
|
||||
.num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
|
||||
|
||||
@ -703,8 +607,6 @@ static int bme280_chip_config(struct bmp280_data *data)
|
||||
}
|
||||
|
||||
static const struct bmp280_chip_info bme280_chip_info = {
|
||||
.regmap_config = &bmp280_regmap_config,
|
||||
|
||||
.oversampling_temp_avail = bmp280_oversampling_avail,
|
||||
.num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
|
||||
|
||||
@ -720,42 +622,6 @@ static const struct bmp280_chip_info bme280_chip_info = {
|
||||
.read_humid = bmp280_read_humid,
|
||||
};
|
||||
|
||||
|
||||
static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
case BMP280_REG_RESET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP180_REG_OUT_XLSB:
|
||||
case BMP180_REG_OUT_LSB:
|
||||
case BMP180_REG_OUT_MSB:
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config bmp180_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = BMP180_REG_OUT_XLSB,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.writeable_reg = bmp180_is_writeable_reg,
|
||||
.volatile_reg = bmp180_is_volatile_reg,
|
||||
};
|
||||
|
||||
static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
|
||||
{
|
||||
int ret;
|
||||
@ -763,16 +629,32 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas)
|
||||
unsigned int delay_us;
|
||||
unsigned int ctrl;
|
||||
|
||||
if (data->use_eoc)
|
||||
init_completion(&data->done);
|
||||
|
||||
ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctrl_meas == BMP180_MEAS_TEMP)
|
||||
delay_us = 4500;
|
||||
else
|
||||
delay_us = conversion_time_max[data->oversampling_press];
|
||||
if (data->use_eoc) {
|
||||
/*
|
||||
* If we have a completion interrupt, use it, wait up to
|
||||
* 100ms. The longest conversion time listed is 76.5 ms for
|
||||
* advanced resolution mode.
|
||||
*/
|
||||
ret = wait_for_completion_timeout(&data->done,
|
||||
1 + msecs_to_jiffies(100));
|
||||
if (!ret)
|
||||
dev_err(data->dev, "timeout waiting for completion\n");
|
||||
} else {
|
||||
if (ctrl_meas == BMP180_MEAS_TEMP)
|
||||
delay_us = 4500;
|
||||
else
|
||||
delay_us =
|
||||
conversion_time_max[data->oversampling_press];
|
||||
|
||||
usleep_range(delay_us, delay_us + 1000);
|
||||
usleep_range(delay_us, delay_us + 1000);
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_CTRL_MEAS, &ctrl);
|
||||
if (ret)
|
||||
@ -803,26 +685,6 @@ static int bmp180_read_adc_temp(struct bmp280_data *data, int *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* These enums are used for indexing into the array of calibration
|
||||
* coefficients for BMP180.
|
||||
*/
|
||||
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
|
||||
|
||||
struct bmp180_calib {
|
||||
s16 AC1;
|
||||
s16 AC2;
|
||||
s16 AC3;
|
||||
u16 AC4;
|
||||
u16 AC5;
|
||||
u16 AC6;
|
||||
s16 B1;
|
||||
s16 B2;
|
||||
s16 MB;
|
||||
s16 MC;
|
||||
s16 MD;
|
||||
};
|
||||
|
||||
static int bmp180_read_calib(struct bmp280_data *data,
|
||||
struct bmp180_calib *calib)
|
||||
{
|
||||
@ -842,6 +704,9 @@ static int bmp180_read_calib(struct bmp280_data *data,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Toss the calibration data into the entropy pool */
|
||||
add_device_randomness(buf, sizeof(buf));
|
||||
|
||||
calib->AC1 = be16_to_cpu(buf[AC1]);
|
||||
calib->AC2 = be16_to_cpu(buf[AC2]);
|
||||
calib->AC3 = be16_to_cpu(buf[AC3]);
|
||||
@ -865,19 +730,11 @@ static int bmp180_read_calib(struct bmp280_data *data,
|
||||
*/
|
||||
static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp)
|
||||
{
|
||||
int ret;
|
||||
s32 x1, x2;
|
||||
struct bmp180_calib calib;
|
||||
struct bmp180_calib *calib = &data->calib;
|
||||
|
||||
ret = bmp180_read_calib(data, &calib);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to read calibration coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
x1 = ((adc_temp - calib.AC6) * calib.AC5) >> 15;
|
||||
x2 = (calib.MC << 11) / (x1 + calib.MD);
|
||||
x1 = ((adc_temp - calib->AC6) * calib->AC5) >> 15;
|
||||
x2 = (calib->MC << 11) / (x1 + calib->MD);
|
||||
data->t_fine = x1 + x2;
|
||||
|
||||
return (data->t_fine + 8) >> 4;
|
||||
@ -932,29 +789,21 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val)
|
||||
*/
|
||||
static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press)
|
||||
{
|
||||
int ret;
|
||||
s32 x1, x2, x3, p;
|
||||
s32 b3, b6;
|
||||
u32 b4, b7;
|
||||
s32 oss = data->oversampling_press;
|
||||
struct bmp180_calib calib;
|
||||
|
||||
ret = bmp180_read_calib(data, &calib);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to read calibration coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
struct bmp180_calib *calib = &data->calib;
|
||||
|
||||
b6 = data->t_fine - 4000;
|
||||
x1 = (calib.B2 * (b6 * b6 >> 12)) >> 11;
|
||||
x2 = calib.AC2 * b6 >> 11;
|
||||
x1 = (calib->B2 * (b6 * b6 >> 12)) >> 11;
|
||||
x2 = calib->AC2 * b6 >> 11;
|
||||
x3 = x1 + x2;
|
||||
b3 = ((((s32)calib.AC1 * 4 + x3) << oss) + 2) / 4;
|
||||
x1 = calib.AC3 * b6 >> 13;
|
||||
x2 = (calib.B1 * ((b6 * b6) >> 12)) >> 16;
|
||||
b3 = ((((s32)calib->AC1 * 4 + x3) << oss) + 2) / 4;
|
||||
x1 = calib->AC3 * b6 >> 13;
|
||||
x2 = (calib->B1 * ((b6 * b6) >> 12)) >> 16;
|
||||
x3 = (x1 + x2 + 2) >> 2;
|
||||
b4 = calib.AC4 * (u32)(x3 + 32768) >> 15;
|
||||
b4 = calib->AC4 * (u32)(x3 + 32768) >> 15;
|
||||
b7 = ((u32)adc_press - b3) * (50000 >> oss);
|
||||
if (b7 < 0x80000000)
|
||||
p = (b7 * 2) / b4;
|
||||
@ -1001,8 +850,6 @@ static const int bmp180_oversampling_temp_avail[] = { 1 };
|
||||
static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 };
|
||||
|
||||
static const struct bmp280_chip_info bmp180_chip_info = {
|
||||
.regmap_config = &bmp180_regmap_config,
|
||||
|
||||
.oversampling_temp_avail = bmp180_oversampling_temp_avail,
|
||||
.num_oversampling_temp_avail =
|
||||
ARRAY_SIZE(bmp180_oversampling_temp_avail),
|
||||
@ -1016,40 +863,86 @@ static const struct bmp280_chip_info bmp180_chip_info = {
|
||||
.read_press = bmp180_read_press,
|
||||
};
|
||||
|
||||
static int bmp280_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static irqreturn_t bmp085_eoc_irq(int irq, void *d)
|
||||
{
|
||||
struct bmp280_data *data = d;
|
||||
|
||||
complete(&data->done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bmp085_fetch_eoc_irq(struct device *dev,
|
||||
const char *name,
|
||||
int irq,
|
||||
struct bmp280_data *data)
|
||||
{
|
||||
unsigned long irq_trig;
|
||||
int ret;
|
||||
|
||||
irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
|
||||
if (irq_trig != IRQF_TRIGGER_RISING) {
|
||||
dev_err(dev, "non-rising trigger given for EOC interrupt, "
|
||||
"trying to enforce it\n");
|
||||
irq_trig = IRQF_TRIGGER_RISING;
|
||||
}
|
||||
ret = devm_request_threaded_irq(dev,
|
||||
irq,
|
||||
bmp085_eoc_irq,
|
||||
NULL,
|
||||
irq_trig,
|
||||
name,
|
||||
data);
|
||||
if (ret) {
|
||||
/* Bail out without IRQ but keep the driver in place */
|
||||
dev_err(dev, "unable to request DRDY IRQ\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->use_eoc = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bmp280_common_probe(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
unsigned int chip,
|
||||
const char *name,
|
||||
int irq)
|
||||
{
|
||||
int ret;
|
||||
struct iio_dev *indio_dev;
|
||||
struct bmp280_data *data;
|
||||
unsigned int chip_id;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
mutex_init(&data->lock);
|
||||
data->client = client;
|
||||
data->dev = dev;
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->name = name;
|
||||
indio_dev->channels = bmp280_channels;
|
||||
indio_dev->info = &bmp280_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
switch (id->driver_data) {
|
||||
switch (chip) {
|
||||
case BMP180_CHIP_ID:
|
||||
indio_dev->num_channels = 2;
|
||||
data->chip_info = &bmp180_chip_info;
|
||||
data->oversampling_press = ilog2(8);
|
||||
data->oversampling_temp = ilog2(1);
|
||||
data->start_up_time = 10;
|
||||
break;
|
||||
case BMP280_CHIP_ID:
|
||||
indio_dev->num_channels = 2;
|
||||
data->chip_info = &bmp280_chip_info;
|
||||
data->oversampling_press = ilog2(16);
|
||||
data->oversampling_temp = ilog2(2);
|
||||
data->start_up_time = 2;
|
||||
break;
|
||||
case BME280_CHIP_ID:
|
||||
indio_dev->num_channels = 3;
|
||||
@ -1057,61 +950,167 @@ static int bmp280_probe(struct i2c_client *client,
|
||||
data->oversampling_press = ilog2(16);
|
||||
data->oversampling_humid = ilog2(16);
|
||||
data->oversampling_temp = ilog2(2);
|
||||
data->start_up_time = 2;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client,
|
||||
data->chip_info->regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
dev_err(&client->dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(data->regmap);
|
||||
/* Bring up regulators */
|
||||
data->vddd = devm_regulator_get(dev, "vddd");
|
||||
if (IS_ERR(data->vddd)) {
|
||||
dev_err(dev, "failed to get VDDD regulator\n");
|
||||
return PTR_ERR(data->vddd);
|
||||
}
|
||||
ret = regulator_enable(data->vddd);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable VDDD regulator\n");
|
||||
return ret;
|
||||
}
|
||||
data->vdda = devm_regulator_get(dev, "vdda");
|
||||
if (IS_ERR(data->vdda)) {
|
||||
dev_err(dev, "failed to get VDDA regulator\n");
|
||||
ret = PTR_ERR(data->vddd);
|
||||
goto out_disable_vddd;
|
||||
}
|
||||
ret = regulator_enable(data->vdda);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable VDDA regulator\n");
|
||||
goto out_disable_vddd;
|
||||
}
|
||||
/* Wait to make sure we started up properly */
|
||||
mdelay(data->start_up_time);
|
||||
|
||||
/* Bring chip out of reset if there is an assigned GPIO line */
|
||||
gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
/* Deassert the signal */
|
||||
if (!IS_ERR(gpiod)) {
|
||||
dev_info(dev, "release reset\n");
|
||||
gpiod_set_value(gpiod, 0);
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_ID, &chip_id);
|
||||
data->regmap = regmap;
|
||||
ret = regmap_read(regmap, BMP280_REG_ID, &chip_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (chip_id != id->driver_data) {
|
||||
dev_err(&client->dev, "bad chip id. expected %lx got %x\n",
|
||||
id->driver_data, chip_id);
|
||||
return -EINVAL;
|
||||
goto out_disable_vdda;
|
||||
if (chip_id != chip) {
|
||||
dev_err(dev, "bad chip id: expected %x got %x\n",
|
||||
chip, chip_id);
|
||||
ret = -EINVAL;
|
||||
goto out_disable_vdda;
|
||||
}
|
||||
|
||||
ret = data->chip_info->chip_config(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto out_disable_vdda;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
|
||||
/*
|
||||
* The BMP085 and BMP180 has calibration in an E2PROM, read it out
|
||||
* at probe time. It will not change.
|
||||
*/
|
||||
if (chip_id == BMP180_CHIP_ID) {
|
||||
ret = bmp180_read_calib(data, &data->calib);
|
||||
if (ret < 0) {
|
||||
dev_err(data->dev,
|
||||
"failed to read calibration coefficients\n");
|
||||
goto out_disable_vdda;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to grab an optional EOC IRQ - only the BMP085 has this
|
||||
* however as it happens, the BMP085 shares the chip ID of BMP180
|
||||
* so we look for an IRQ if we have that.
|
||||
*/
|
||||
if (irq > 0 || (chip_id == BMP180_CHIP_ID)) {
|
||||
ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
|
||||
if (ret)
|
||||
goto out_disable_vdda;
|
||||
}
|
||||
|
||||
/* Enable runtime PM */
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
/*
|
||||
* Set autosuspend to two orders of magnitude larger than the
|
||||
* start-up time.
|
||||
*/
|
||||
pm_runtime_set_autosuspend_delay(dev, data->start_up_time *100);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto out_runtime_pm_disable;
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
out_runtime_pm_disable:
|
||||
pm_runtime_get_sync(data->dev);
|
||||
pm_runtime_put_noidle(data->dev);
|
||||
pm_runtime_disable(data->dev);
|
||||
out_disable_vdda:
|
||||
regulator_disable(data->vdda);
|
||||
out_disable_vddd:
|
||||
regulator_disable(data->vddd);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(bmp280_common_probe);
|
||||
|
||||
int bmp280_common_remove(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct bmp280_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
pm_runtime_get_sync(data->dev);
|
||||
pm_runtime_put_noidle(data->dev);
|
||||
pm_runtime_disable(data->dev);
|
||||
regulator_disable(data->vdda);
|
||||
regulator_disable(data->vddd);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(bmp280_common_remove);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bmp280_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct bmp280_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = regulator_disable(data->vdda);
|
||||
if (ret)
|
||||
return ret;
|
||||
return regulator_disable(data->vddd);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id bmp280_acpi_match[] = {
|
||||
{"BMP0280", BMP280_CHIP_ID },
|
||||
{"BMP0180", BMP180_CHIP_ID },
|
||||
{"BMP0085", BMP180_CHIP_ID },
|
||||
{"BME0280", BME280_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match);
|
||||
static int bmp280_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct bmp280_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
static const struct i2c_device_id bmp280_id[] = {
|
||||
{"bmp280", BMP280_CHIP_ID },
|
||||
{"bmp180", BMP180_CHIP_ID },
|
||||
{"bmp085", BMP180_CHIP_ID },
|
||||
{"bme280", BME280_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bmp280_id);
|
||||
ret = regulator_enable(data->vddd);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regulator_enable(data->vdda);
|
||||
if (ret)
|
||||
return ret;
|
||||
msleep(data->start_up_time);
|
||||
return data->chip_info->chip_config(data);
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct i2c_driver bmp280_driver = {
|
||||
.driver = {
|
||||
.name = "bmp280",
|
||||
.acpi_match_table = ACPI_PTR(bmp280_acpi_match),
|
||||
},
|
||||
.probe = bmp280_probe,
|
||||
.id_table = bmp280_id,
|
||||
const struct dev_pm_ops bmp280_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(bmp280_runtime_suspend,
|
||||
bmp280_runtime_resume, NULL)
|
||||
};
|
||||
module_i2c_driver(bmp280_driver);
|
||||
EXPORT_SYMBOL(bmp280_dev_pm_ops);
|
||||
|
||||
MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
|
||||
MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor");
|
91
drivers/iio/pressure/bmp280-i2c.c
Normal file
91
drivers/iio/pressure/bmp280-i2c.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "bmp280.h"
|
||||
|
||||
static int bmp280_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const struct regmap_config *regmap_config;
|
||||
|
||||
switch (id->driver_data) {
|
||||
case BMP180_CHIP_ID:
|
||||
regmap_config = &bmp180_regmap_config;
|
||||
break;
|
||||
case BMP280_CHIP_ID:
|
||||
case BME280_CHIP_ID:
|
||||
regmap_config = &bmp280_regmap_config;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return bmp280_common_probe(&client->dev,
|
||||
regmap,
|
||||
id->driver_data,
|
||||
id->name,
|
||||
client->irq);
|
||||
}
|
||||
|
||||
static int bmp280_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
return bmp280_common_remove(&client->dev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id bmp280_acpi_i2c_match[] = {
|
||||
{"BMP0280", BMP280_CHIP_ID },
|
||||
{"BMP0180", BMP180_CHIP_ID },
|
||||
{"BMP0085", BMP180_CHIP_ID },
|
||||
{"BME0280", BME280_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bmp280_acpi_i2c_match);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id bmp280_of_i2c_match[] = {
|
||||
{ .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID },
|
||||
{ .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID },
|
||||
{ .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID },
|
||||
{ .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
|
||||
#else
|
||||
#define bmp280_of_i2c_match NULL
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id bmp280_i2c_id[] = {
|
||||
{"bmp280", BMP280_CHIP_ID },
|
||||
{"bmp180", BMP180_CHIP_ID },
|
||||
{"bmp085", BMP180_CHIP_ID },
|
||||
{"bme280", BME280_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id);
|
||||
|
||||
static struct i2c_driver bmp280_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "bmp280",
|
||||
.acpi_match_table = ACPI_PTR(bmp280_acpi_i2c_match),
|
||||
.of_match_table = of_match_ptr(bmp280_of_i2c_match),
|
||||
.pm = &bmp280_dev_pm_ops,
|
||||
},
|
||||
.probe = bmp280_i2c_probe,
|
||||
.remove = bmp280_i2c_remove,
|
||||
.id_table = bmp280_i2c_id,
|
||||
};
|
||||
module_i2c_driver(bmp280_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
|
||||
MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
84
drivers/iio/pressure/bmp280-regmap.c
Normal file
84
drivers/iio/pressure/bmp280-regmap.c
Normal file
@ -0,0 +1,84 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "bmp280.h"
|
||||
|
||||
static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
case BMP280_REG_RESET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP180_REG_OUT_XLSB:
|
||||
case BMP180_REG_OUT_LSB:
|
||||
case BMP180_REG_OUT_MSB:
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const struct regmap_config bmp180_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = BMP180_REG_OUT_XLSB,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.writeable_reg = bmp180_is_writeable_reg,
|
||||
.volatile_reg = bmp180_is_volatile_reg,
|
||||
};
|
||||
EXPORT_SYMBOL(bmp180_regmap_config);
|
||||
|
||||
static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_CONFIG:
|
||||
case BMP280_REG_CTRL_HUMIDITY:
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
case BMP280_REG_RESET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_HUMIDITY_LSB:
|
||||
case BMP280_REG_HUMIDITY_MSB:
|
||||
case BMP280_REG_TEMP_XLSB:
|
||||
case BMP280_REG_TEMP_LSB:
|
||||
case BMP280_REG_TEMP_MSB:
|
||||
case BMP280_REG_PRESS_XLSB:
|
||||
case BMP280_REG_PRESS_LSB:
|
||||
case BMP280_REG_PRESS_MSB:
|
||||
case BMP280_REG_STATUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const struct regmap_config bmp280_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = BMP280_REG_HUMIDITY_LSB,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.writeable_reg = bmp280_is_writeable_reg,
|
||||
.volatile_reg = bmp280_is_volatile_reg,
|
||||
};
|
||||
EXPORT_SYMBOL(bmp280_regmap_config);
|
125
drivers/iio/pressure/bmp280-spi.c
Normal file
125
drivers/iio/pressure/bmp280-spi.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* SPI interface for the BMP280 driver
|
||||
*
|
||||
* Inspired by the older BMP085 driver drivers/misc/bmp085-spi.c
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "bmp280.h"
|
||||
|
||||
static int bmp280_regmap_spi_write(void *context, const void *data,
|
||||
size_t count)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
u8 buf[2];
|
||||
|
||||
memcpy(buf, data, 2);
|
||||
/*
|
||||
* The SPI register address (= full register address without bit 7) and
|
||||
* the write command (bit7 = RW = '0')
|
||||
*/
|
||||
buf[0] &= ~0x80;
|
||||
|
||||
return spi_write_then_read(spi, buf, 2, NULL, 0);
|
||||
}
|
||||
|
||||
static int bmp280_regmap_spi_read(void *context, const void *reg,
|
||||
size_t reg_size, void *val, size_t val_size)
|
||||
{
|
||||
struct device *dev = context;
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
return spi_write_then_read(spi, reg, reg_size, val, val_size);
|
||||
}
|
||||
|
||||
static struct regmap_bus bmp280_regmap_bus = {
|
||||
.write = bmp280_regmap_spi_write,
|
||||
.read = bmp280_regmap_spi_read,
|
||||
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||
.val_format_endian_default = REGMAP_ENDIAN_BIG,
|
||||
};
|
||||
|
||||
static int bmp280_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
struct regmap *regmap;
|
||||
const struct regmap_config *regmap_config;
|
||||
int ret;
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "spi_setup failed!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (id->driver_data) {
|
||||
case BMP180_CHIP_ID:
|
||||
regmap_config = &bmp180_regmap_config;
|
||||
break;
|
||||
case BMP280_CHIP_ID:
|
||||
case BME280_CHIP_ID:
|
||||
regmap_config = &bmp280_regmap_config;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init(&spi->dev,
|
||||
&bmp280_regmap_bus,
|
||||
&spi->dev,
|
||||
regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "failed to allocate register map\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return bmp280_common_probe(&spi->dev,
|
||||
regmap,
|
||||
id->driver_data,
|
||||
id->name,
|
||||
spi->irq);
|
||||
}
|
||||
|
||||
static int bmp280_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return bmp280_common_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id bmp280_of_spi_match[] = {
|
||||
{ .compatible = "bosch,bmp085", },
|
||||
{ .compatible = "bosch,bmp180", },
|
||||
{ .compatible = "bosch,bmp181", },
|
||||
{ .compatible = "bosch,bmp280", },
|
||||
{ .compatible = "bosch,bme280", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
|
||||
|
||||
static const struct spi_device_id bmp280_spi_id[] = {
|
||||
{ "bmp180", BMP180_CHIP_ID },
|
||||
{ "bmp181", BMP180_CHIP_ID },
|
||||
{ "bmp280", BMP280_CHIP_ID },
|
||||
{ "bme280", BME280_CHIP_ID },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, bmp280_spi_id);
|
||||
|
||||
static struct spi_driver bmp280_spi_driver = {
|
||||
.driver = {
|
||||
.name = "bmp280",
|
||||
.of_match_table = bmp280_of_spi_match,
|
||||
.pm = &bmp280_dev_pm_ops,
|
||||
},
|
||||
.id_table = bmp280_spi_id,
|
||||
.probe = bmp280_spi_probe,
|
||||
.remove = bmp280_spi_remove,
|
||||
};
|
||||
module_spi_driver(bmp280_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("BMP280 SPI bus driver");
|
||||
MODULE_LICENSE("GPL");
|
112
drivers/iio/pressure/bmp280.h
Normal file
112
drivers/iio/pressure/bmp280.h
Normal file
@ -0,0 +1,112 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* BMP280 specific registers */
|
||||
#define BMP280_REG_HUMIDITY_LSB 0xFE
|
||||
#define BMP280_REG_HUMIDITY_MSB 0xFD
|
||||
#define BMP280_REG_TEMP_XLSB 0xFC
|
||||
#define BMP280_REG_TEMP_LSB 0xFB
|
||||
#define BMP280_REG_TEMP_MSB 0xFA
|
||||
#define BMP280_REG_PRESS_XLSB 0xF9
|
||||
#define BMP280_REG_PRESS_LSB 0xF8
|
||||
#define BMP280_REG_PRESS_MSB 0xF7
|
||||
|
||||
#define BMP280_REG_CONFIG 0xF5
|
||||
#define BMP280_REG_CTRL_MEAS 0xF4
|
||||
#define BMP280_REG_STATUS 0xF3
|
||||
#define BMP280_REG_CTRL_HUMIDITY 0xF2
|
||||
|
||||
/* Due to non linear mapping, and data sizes we can't do a bulk read */
|
||||
#define BMP280_REG_COMP_H1 0xA1
|
||||
#define BMP280_REG_COMP_H2 0xE1
|
||||
#define BMP280_REG_COMP_H3 0xE3
|
||||
#define BMP280_REG_COMP_H4 0xE4
|
||||
#define BMP280_REG_COMP_H5 0xE5
|
||||
#define BMP280_REG_COMP_H6 0xE7
|
||||
|
||||
#define BMP280_REG_COMP_TEMP_START 0x88
|
||||
#define BMP280_COMP_TEMP_REG_COUNT 6
|
||||
|
||||
#define BMP280_REG_COMP_PRESS_START 0x8E
|
||||
#define BMP280_COMP_PRESS_REG_COUNT 18
|
||||
|
||||
#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2))
|
||||
#define BMP280_FILTER_OFF 0
|
||||
#define BMP280_FILTER_2X BIT(2)
|
||||
#define BMP280_FILTER_4X BIT(3)
|
||||
#define BMP280_FILTER_8X (BIT(3) | BIT(2))
|
||||
#define BMP280_FILTER_16X BIT(4)
|
||||
|
||||
#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0))
|
||||
#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0)
|
||||
#define BMP280_OSRS_HUMIDITY_SKIP 0
|
||||
#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1)
|
||||
#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2)
|
||||
#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3)
|
||||
#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4)
|
||||
#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5)
|
||||
|
||||
#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5))
|
||||
#define BMP280_OSRS_TEMP_SKIP 0
|
||||
#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5)
|
||||
#define BMP280_OSRS_TEMP_1X BMP280_OSRS_TEMP_X(1)
|
||||
#define BMP280_OSRS_TEMP_2X BMP280_OSRS_TEMP_X(2)
|
||||
#define BMP280_OSRS_TEMP_4X BMP280_OSRS_TEMP_X(3)
|
||||
#define BMP280_OSRS_TEMP_8X BMP280_OSRS_TEMP_X(4)
|
||||
#define BMP280_OSRS_TEMP_16X BMP280_OSRS_TEMP_X(5)
|
||||
|
||||
#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2))
|
||||
#define BMP280_OSRS_PRESS_SKIP 0
|
||||
#define BMP280_OSRS_PRESS_X(osrs_p) ((osrs_p) << 2)
|
||||
#define BMP280_OSRS_PRESS_1X BMP280_OSRS_PRESS_X(1)
|
||||
#define BMP280_OSRS_PRESS_2X BMP280_OSRS_PRESS_X(2)
|
||||
#define BMP280_OSRS_PRESS_4X BMP280_OSRS_PRESS_X(3)
|
||||
#define BMP280_OSRS_PRESS_8X BMP280_OSRS_PRESS_X(4)
|
||||
#define BMP280_OSRS_PRESS_16X BMP280_OSRS_PRESS_X(5)
|
||||
|
||||
#define BMP280_MODE_MASK (BIT(1) | BIT(0))
|
||||
#define BMP280_MODE_SLEEP 0
|
||||
#define BMP280_MODE_FORCED BIT(0)
|
||||
#define BMP280_MODE_NORMAL (BIT(1) | BIT(0))
|
||||
|
||||
/* BMP180 specific registers */
|
||||
#define BMP180_REG_OUT_XLSB 0xF8
|
||||
#define BMP180_REG_OUT_LSB 0xF7
|
||||
#define BMP180_REG_OUT_MSB 0xF6
|
||||
|
||||
#define BMP180_REG_CALIB_START 0xAA
|
||||
#define BMP180_REG_CALIB_COUNT 22
|
||||
|
||||
#define BMP180_MEAS_SCO BIT(5)
|
||||
#define BMP180_MEAS_TEMP (0x0E | BMP180_MEAS_SCO)
|
||||
#define BMP180_MEAS_PRESS_X(oss) ((oss) << 6 | 0x14 | BMP180_MEAS_SCO)
|
||||
#define BMP180_MEAS_PRESS_1X BMP180_MEAS_PRESS_X(0)
|
||||
#define BMP180_MEAS_PRESS_2X BMP180_MEAS_PRESS_X(1)
|
||||
#define BMP180_MEAS_PRESS_4X BMP180_MEAS_PRESS_X(2)
|
||||
#define BMP180_MEAS_PRESS_8X BMP180_MEAS_PRESS_X(3)
|
||||
|
||||
/* BMP180 and BMP280 common registers */
|
||||
#define BMP280_REG_CTRL_MEAS 0xF4
|
||||
#define BMP280_REG_RESET 0xE0
|
||||
#define BMP280_REG_ID 0xD0
|
||||
|
||||
#define BMP180_CHIP_ID 0x55
|
||||
#define BMP280_CHIP_ID 0x58
|
||||
#define BME280_CHIP_ID 0x60
|
||||
#define BMP280_SOFT_RESET_VAL 0xB6
|
||||
|
||||
/* Regmap configurations */
|
||||
extern const struct regmap_config bmp180_regmap_config;
|
||||
extern const struct regmap_config bmp280_regmap_config;
|
||||
|
||||
/* Probe called from different transports */
|
||||
int bmp280_common_probe(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
unsigned int chip,
|
||||
const char *name,
|
||||
int irq);
|
||||
int bmp280_common_remove(struct device *dev);
|
||||
|
||||
/* PM ops */
|
||||
extern const struct dev_pm_ops bmp280_dev_pm_ops;
|
@ -171,7 +171,7 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p)
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -224,7 +224,8 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, buf,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
@ -28,6 +28,72 @@
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
#include "st_pressure.h"
|
||||
|
||||
/*
|
||||
* About determining pressure scaling factors
|
||||
* ------------------------------------------
|
||||
*
|
||||
* Datasheets specify typical pressure sensitivity so that pressure is computed
|
||||
* according to the following equation :
|
||||
* pressure[mBar] = raw / sensitivity
|
||||
* where :
|
||||
* raw the 24 bits long raw sampled pressure
|
||||
* sensitivity a scaling factor specified by the datasheet in LSB/mBar
|
||||
*
|
||||
* IIO ABI expects pressure to be expressed as kPascal, hence pressure should be
|
||||
* computed according to :
|
||||
* pressure[kPascal] = pressure[mBar] / 10
|
||||
* = raw / (sensitivity * 10) (1)
|
||||
*
|
||||
* Finally, st_press_read_raw() returns pressure scaling factor as an
|
||||
* IIO_VAL_INT_PLUS_NANO with a zero integral part and "gain" as decimal part.
|
||||
* Therefore, from (1), "gain" becomes :
|
||||
* gain = 10^9 / (sensitivity * 10)
|
||||
* = 10^8 / sensitivity
|
||||
*
|
||||
* About determining temperature scaling factors and offsets
|
||||
* ---------------------------------------------------------
|
||||
*
|
||||
* Datasheets specify typical temperature sensitivity and offset so that
|
||||
* temperature is computed according to the following equation :
|
||||
* temp[Celsius] = offset[Celsius] + (raw / sensitivity)
|
||||
* where :
|
||||
* raw the 16 bits long raw sampled temperature
|
||||
* offset a constant specified by the datasheet in degree Celsius
|
||||
* (sometimes zero)
|
||||
* sensitivity a scaling factor specified by the datasheet in LSB/Celsius
|
||||
*
|
||||
* IIO ABI expects temperature to be expressed as milli degree Celsius such as
|
||||
* user space should compute temperature according to :
|
||||
* temp[mCelsius] = temp[Celsius] * 10^3
|
||||
* = (offset[Celsius] + (raw / sensitivity)) * 10^3
|
||||
* = ((offset[Celsius] * sensitivity) + raw) *
|
||||
* (10^3 / sensitivity) (2)
|
||||
*
|
||||
* IIO ABI expects user space to apply offset and scaling factors to raw samples
|
||||
* according to :
|
||||
* temp[mCelsius] = (OFFSET + raw) * SCALE
|
||||
* where :
|
||||
* OFFSET an arbitrary constant exposed by device
|
||||
* SCALE an arbitrary scaling factor exposed by device
|
||||
*
|
||||
* Matching OFFSET and SCALE with members of (2) gives :
|
||||
* OFFSET = offset[Celsius] * sensitivity (3)
|
||||
* SCALE = 10^3 / sensitivity (4)
|
||||
*
|
||||
* st_press_read_raw() returns temperature scaling factor as an
|
||||
* IIO_VAL_FRACTIONAL with a 10^3 numerator and "gain2" as denominator.
|
||||
* Therefore, from (3), "gain2" becomes :
|
||||
* gain2 = sensitivity
|
||||
*
|
||||
* When declared within channel, i.e. for a non zero specified offset,
|
||||
* st_press_read_raw() will return the latter as an IIO_VAL_FRACTIONAL such as :
|
||||
* numerator = OFFSET * 10^3
|
||||
* denominator = 10^3
|
||||
* giving from (4):
|
||||
* numerator = offset[Celsius] * 10^3 * sensitivity
|
||||
* = offset[mCelsius] * gain2
|
||||
*/
|
||||
|
||||
#define MCELSIUS_PER_CELSIUS 1000
|
||||
|
||||
/* Default pressure sensitivity */
|
||||
@ -39,8 +105,6 @@
|
||||
#define ST_PRESS_LSB_PER_CELSIUS 480UL
|
||||
#define ST_PRESS_MILLI_CELSIUS_OFFSET 42500UL
|
||||
|
||||
#define ST_PRESS_NUMBER_DATA_CHANNELS 1
|
||||
|
||||
/* FULLSCALE */
|
||||
#define ST_PRESS_FS_AVL_1100MB 1100
|
||||
#define ST_PRESS_FS_AVL_1260MB 1260
|
||||
@ -48,7 +112,11 @@
|
||||
#define ST_PRESS_1_OUT_XL_ADDR 0x28
|
||||
#define ST_TEMP_1_OUT_L_ADDR 0x2b
|
||||
|
||||
/* CUSTOM VALUES FOR LPS331AP SENSOR */
|
||||
/*
|
||||
* CUSTOM VALUES FOR LPS331AP SENSOR
|
||||
* See LPS331AP datasheet:
|
||||
* http://www2.st.com/resource/en/datasheet/lps331ap.pdf
|
||||
*/
|
||||
#define ST_PRESS_LPS331AP_WAI_EXP 0xbb
|
||||
#define ST_PRESS_LPS331AP_ODR_ADDR 0x20
|
||||
#define ST_PRESS_LPS331AP_ODR_MASK 0x70
|
||||
@ -71,7 +139,9 @@
|
||||
#define ST_PRESS_LPS331AP_OD_IRQ_MASK 0x40
|
||||
#define ST_PRESS_LPS331AP_MULTIREAD_BIT true
|
||||
|
||||
/* CUSTOM VALUES FOR LPS001WP SENSOR */
|
||||
/*
|
||||
* CUSTOM VALUES FOR THE OBSOLETE LPS001WP SENSOR
|
||||
*/
|
||||
|
||||
/* LPS001WP pressure resolution */
|
||||
#define ST_PRESS_LPS001WP_LSB_PER_MBAR 16UL
|
||||
@ -94,7 +164,11 @@
|
||||
#define ST_PRESS_LPS001WP_OUT_L_ADDR 0x28
|
||||
#define ST_TEMP_LPS001WP_OUT_L_ADDR 0x2a
|
||||
|
||||
/* CUSTOM VALUES FOR LPS25H SENSOR */
|
||||
/*
|
||||
* CUSTOM VALUES FOR LPS25H SENSOR
|
||||
* See LPS25H datasheet:
|
||||
* http://www2.st.com/resource/en/datasheet/lps25h.pdf
|
||||
*/
|
||||
#define ST_PRESS_LPS25H_WAI_EXP 0xbd
|
||||
#define ST_PRESS_LPS25H_ODR_ADDR 0x20
|
||||
#define ST_PRESS_LPS25H_ODR_MASK 0x70
|
||||
@ -117,7 +191,15 @@
|
||||
#define ST_PRESS_LPS25H_OUT_XL_ADDR 0x28
|
||||
#define ST_TEMP_LPS25H_OUT_L_ADDR 0x2b
|
||||
|
||||
/* CUSTOM VALUES FOR LPS22HB SENSOR */
|
||||
/*
|
||||
* CUSTOM VALUES FOR LPS22HB SENSOR
|
||||
* See LPS22HB datasheet:
|
||||
* http://www2.st.com/resource/en/datasheet/lps22hb.pdf
|
||||
*/
|
||||
|
||||
/* LPS22HB temperature sensitivity */
|
||||
#define ST_PRESS_LPS22HB_LSB_PER_CELSIUS 100UL
|
||||
|
||||
#define ST_PRESS_LPS22HB_WAI_EXP 0xb1
|
||||
#define ST_PRESS_LPS22HB_ODR_ADDR 0x10
|
||||
#define ST_PRESS_LPS22HB_ODR_MASK 0x70
|
||||
@ -135,29 +217,28 @@
|
||||
#define ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK 0x08
|
||||
#define ST_PRESS_LPS22HB_IHL_IRQ_ADDR 0x12
|
||||
#define ST_PRESS_LPS22HB_IHL_IRQ_MASK 0x80
|
||||
#define ST_PRESS_LPS22HB_OD_IRQ_ADDR 0x12
|
||||
#define ST_PRESS_LPS22HB_OD_IRQ_MASK 0x40
|
||||
#define ST_PRESS_LPS22HB_MULTIREAD_BIT true
|
||||
|
||||
static const struct iio_chan_spec st_press_1_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.address = ST_PRESS_1_OUT_XL_ADDR,
|
||||
.scan_index = ST_SENSORS_SCAN_X,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 24,
|
||||
.storagebits = 24,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
.modified = 0,
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.address = ST_TEMP_1_OUT_L_ADDR,
|
||||
.scan_index = -1,
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
@ -168,17 +249,15 @@ static const struct iio_chan_spec st_press_1_channels[] = {
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
.modified = 0,
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1)
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_press_lps001wp_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.address = ST_PRESS_LPS001WP_OUT_L_ADDR,
|
||||
.scan_index = ST_SENSORS_SCAN_X,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
@ -188,13 +267,11 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.modified = 0,
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.address = ST_TEMP_LPS001WP_OUT_L_ADDR,
|
||||
.scan_index = -1,
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
@ -204,30 +281,42 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.modified = 0,
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1)
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_press_lps22hb_channels[] = {
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.channel2 = IIO_NO_MOD,
|
||||
.address = ST_PRESS_1_OUT_XL_ADDR,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 24,
|
||||
.storagebits = 24,
|
||||
.storagebits = 32,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.modified = 0,
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1)
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.address = ST_TEMP_1_OUT_L_ADDR,
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2)
|
||||
};
|
||||
|
||||
static const struct st_sensor_settings st_press_sensors_settings[] = {
|
||||
@ -413,9 +502,14 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
|
||||
},
|
||||
.fs = {
|
||||
.fs_avl = {
|
||||
/*
|
||||
* Pressure and temperature sensitivity values
|
||||
* as defined in table 3 of LPS22HB datasheet.
|
||||
*/
|
||||
[0] = {
|
||||
.num = ST_PRESS_FS_AVL_1260MB,
|
||||
.gain = ST_PRESS_KPASCAL_NANO_SCALE,
|
||||
.gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -429,6 +523,9 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
|
||||
.mask_int2 = ST_PRESS_LPS22HB_DRDY_IRQ_INT2_MASK,
|
||||
.addr_ihl = ST_PRESS_LPS22HB_IHL_IRQ_ADDR,
|
||||
.mask_ihl = ST_PRESS_LPS22HB_IHL_IRQ_MASK,
|
||||
.addr_od = ST_PRESS_LPS22HB_OD_IRQ_ADDR,
|
||||
.mask_od = ST_PRESS_LPS22HB_OD_IRQ_MASK,
|
||||
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
|
||||
},
|
||||
.multi_read_bit = ST_PRESS_LPS22HB_MULTIREAD_BIT,
|
||||
},
|
||||
@ -558,7 +655,13 @@ int st_press_common_probe(struct iio_dev *indio_dev)
|
||||
if (err < 0)
|
||||
goto st_press_power_off;
|
||||
|
||||
press_data->num_data_channels = ST_PRESS_NUMBER_DATA_CHANNELS;
|
||||
/*
|
||||
* Skip timestamping channel while declaring available channels to
|
||||
* common st_sensor layer. Look at st_sensors_get_buffer_element() to
|
||||
* see how timestamps are explicitly pushed as last samples block
|
||||
* element.
|
||||
*/
|
||||
press_data->num_data_channels = press_data->sensor_settings->num_ch - 1;
|
||||
press_data->multiread_bit = press_data->sensor_settings->multi_read_bit;
|
||||
indio_dev->channels = press_data->sensor_settings->ch;
|
||||
indio_dev->num_channels = press_data->sensor_settings->num_ch;
|
||||
|
@ -238,7 +238,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private)
|
||||
ret = lidar_get_measurement(data, data->buffer);
|
||||
if (!ret) {
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
} else if (ret != -EINVAL) {
|
||||
dev_err(&data->client->dev, "cannot read LIDAR measurement");
|
||||
}
|
||||
|
@ -492,7 +492,7 @@ static void sx9500_push_events(struct iio_dev *indio_dev)
|
||||
dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
|
||||
ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
|
||||
IIO_EV_TYPE_THRESH, dir);
|
||||
iio_push_event(indio_dev, ev, iio_get_time_ns());
|
||||
iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
|
||||
data->prox_stat[chan] = new_prox;
|
||||
}
|
||||
}
|
||||
@ -669,7 +669,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private)
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
out:
|
||||
mutex_unlock(&data->mutex);
|
||||
|
@ -51,20 +51,6 @@ config ADIS16240
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16240.
|
||||
|
||||
config LIS3L02DQ
|
||||
tristate "ST Microelectronics LIS3L02DQ Accelerometer Driver"
|
||||
depends on SPI
|
||||
select IIO_TRIGGER if IIO_BUFFER
|
||||
depends on !IIO_BUFFER || IIO_KFIFO_BUF
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
help
|
||||
Say Y here to build SPI support for the ST microelectronics
|
||||
accelerometer. The driver supplies direct access via sysfs files
|
||||
and an event interface via a character device.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called lis3l02dq.
|
||||
|
||||
config SCA3000
|
||||
depends on IIO_BUFFER
|
||||
depends on SPI
|
||||
|
@ -14,9 +14,5 @@ obj-$(CONFIG_ADIS16209) += adis16209.o
|
||||
adis16240-y := adis16240_core.o
|
||||
obj-$(CONFIG_ADIS16240) += adis16240.o
|
||||
|
||||
lis3l02dq-y := lis3l02dq_core.o
|
||||
lis3l02dq-$(CONFIG_IIO_BUFFER) += lis3l02dq_ring.o
|
||||
obj-$(CONFIG_LIS3L02DQ) += lis3l02dq.o
|
||||
|
||||
sca3000-y := sca3000_core.o sca3000_ring.o
|
||||
obj-$(CONFIG_SCA3000) += sca3000.o
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user