Staging / IIO driver update for 4.8-rc1

Here is the big Staging and IIO driver update for 4.8-rc1.
 
 We ended up adding more code than removing, again, but it's not all that
 bad.  Lots of cleanups all over the staging tree, and new IIO drivers,
 full details in the shortlog.
 
 All of these have been in linux-next for a while with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iFYEABECABYFAleVPQQPHGdyZWdAa3JvYWguY29tAAoJEDFH1A3bLfsplRgAniG6
 jfPnvlHhl70T5HsGJzrc7VS9AKCBQ5x0gzTNxo2nnGfPmR8CVEH7Bg==
 =0/6X
 -----END PGP SIGNATURE-----

Merge tag 'staging-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging and IIO driver updates from Greg KH:
 "Here is the big Staging and IIO driver update for 4.8-rc1.

  We ended up adding more code than removing, again, but it's not all
  that bad.  Lots of cleanups all over the staging tree, and new IIO
  drivers, full details in the shortlog.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'staging-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (417 commits)
  drivers:iio:accel:mma8452: removed unwanted return statements
  drivers:iio:accel:mma8452: added cleanup provision in case of failure.
  iio: Add iio.git tree to MAINTAINERS
  iio:st_pressure: clean useless static channel initializers
  iio:st_pressure:lps22hb: temperature support
  iio:st_pressure:lps22hb: open drain support
  iio:st_pressure: temperature triggered buffering
  iio:st_pressure: document sampling gains
  iio:st_pressure: align storagebits on power of 2
  iio:st_sensors: align on storagebits boundaries
  staging:iio:lis3l02dq drop separate driver
  iio: accel: st_accel: Add lis3l02dq support
  iio: adc: add missing of_node references to iio_dev
  iio: adc: ti-ads1015: add indio_dev->dev.of_node reference
  iio: potentiometer: Fix typo in Kconfig
  iio: potentiometer: mcp4531: Add device tree binding
  iio: potentiometer: mcp4531: Add device tree binding documentation
  iio: potentiometer: mcp4531: Add support for MCP454x, MCP456x, MCP464x and MCP466x
  iio:imu:mpu6050: icm20608 initial support
  iio: adc: max1363: Add device tree binding
  ...
This commit is contained in:
Linus Torvalds 2016-07-24 16:55:23 -07:00
commit 25a0dc4be8
529 changed files with 22425 additions and 12689 deletions

View File

@ -11,6 +11,7 @@ Aaron Durbin <adurbin@google.com>
Adam Oldham <oldhamca@gmail.com>
Adam Radford <aradford@gmail.com>
Adrian Bunk <bunk@stusta.de>
Adriana Reus <adi.reus@gmail.com> <adriana.reus@intel.com>
Alan Cox <alan@lxorguk.ukuu.org.uk>
Alan Cox <root@hraefn.swansea.linux.org.uk>
Aleksey Gorelov <aleksey_gorelov@phoenix.com>
@ -94,6 +95,8 @@ Linas Vepstas <linas@austin.ibm.com>
Mark Brown <broonie@sirena.org.uk>
Matthieu CASTET <castet.matthieu@free.fr>
Mauro Carvalho Chehab <mchehab@kernel.org> <maurochehab@gmail.com> <mchehab@infradead.org> <mchehab@redhat.com> <m.chehab@samsung.com> <mchehab@osg.samsung.com> <mchehab@s-opensource.com>
Matt Ranostay <mranostay@gmail.com> Matthew Ranostay <mranostay@embeddedalley.com>
Matt Ranostay <mranostay@gmail.com> <matt.ranostay@intel.com>
Mayuresh Janorkar <mayur@ti.com>
Michael Buesch <m@bues.ch>
Michel Dänzer <michel@tungstengraphics.com>

View File

@ -19,3 +19,16 @@ KernelVersion: 4.4
Description:
High resolution timers directory. Creating a directory here
will result in creating a hrtimer trigger in the IIO subsystem.
What: /config/iio/devices
Date: April 2016
KernelVersion: 4.7
Description:
Industrial IO software devices directory.
What: /config/iio/devices/dummy
Date: April 2016
KernelVersion: 4.7
Description:
Dummy IIO devices directory. Creating a directory here will result
in creating a dummy IIO device in the IIO subystem.

View File

@ -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
@ -1565,3 +1572,10 @@ Description:
* X is in the plane of the propellers, perpendicular to Y axis,
and positive towards the starboard side of the UAV ;
* Z is perpendicular to propellers plane and positive upwards.
What: /sys/bus/iio/devices/iio:deviceX/in_electricalconductivity_raw
KernelVersion: 4.8
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) electric conductivity reading that
can be processed to siemens per meter.

View File

@ -1,54 +1,41 @@
What: /sys/bus/iio/devices/iio:deviceX/tia_resistanceY
/sys/bus/iio/devices/iio:deviceX/tia_capacitanceY
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the resistance and the capacitance settings for the
Transimpedance Amplifier. Y is 1 for Rf1 and Cf1, Y is 2 for
Rf2 and Cf2 values.
What: /sys/bus/iio/devices/iio:deviceX/tia_separate_en
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Enable or disable separate settings for the TransImpedance
Amplifier above, when disabled both values are set by the
first channel.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_raw
/sys/bus/iio/devices/iio:deviceX/in_intensity_ledY_ambient_raw
Date: December 2015
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_raw
Date: May 2016
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get measured values from the ADC for these stages. Y is the
specific LED number. The values are expressed in 24-bit twos
complement.
specific stage number corresponding to datasheet stage names
as follows:
1 -> LED2
2 -> ALED2/LED3
3 -> LED1
4 -> ALED1/LED4
Note that channels 5 and 6 represent LED2-ALED2 and LED1-ALED1
respectively which simply helper channels containing the
calculated difference in the value of stage 1 - 2 and 3 - 4.
The values are expressed in 24-bit twos complement.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ledY-ledY_ambient_raw
Date: December 2015
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get differential values from the ADC for these stages. Y is the
specific LED number. The values are expressed in 24-bit twos
complement for the specified LEDs.
What: /sys/bus/iio/devices/iio:deviceX/out_current_ledY_offset
/sys/bus/iio/devices/iio:deviceX/out_current_ledY_ambient_offset
Date: December 2015
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_offset
Date: May 2016
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the offset cancellation DAC setting for these
stages. The values are expressed in 5-bit sign-magnitude.
What: /sys/bus/iio/devices/iio:deviceX/out_current_ledY_raw
Date: December 2015
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_resistance
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_capacitance
Date: May 2016
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the LED current for the specified LED. Y is the
specific LED number.
Get and set the resistance and the capacitance settings for the
Transimpedance Amplifier during the associated stage.
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw
Date: May 2016
KernelVersion:
Contact: Andrew F. Davis <afd@ti.com>
Description:
Get and set the LED current for the specified LED active during
this stage. Y is the specific stage number.

View File

@ -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;
}

View File

@ -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

View File

@ -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";
};

View 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>;
};

View File

@ -0,0 +1,22 @@
* Atlas Scientific EC-SM OEM sensor
http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf
Required properties:
- compatible: must be "atlas,ec-sm"
- reg: the I2C address of the sensor
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: the sole interrupt generated by the device
Refer to interrupt-controller/interrupts.txt for generic interrupt client
node bindings.
Example:
atlas@64 {
compatible = "atlas,ec-sm";
reg = <0x64>;
interrupt-parent = <&gpio1>;
interrupts = <16 2>;
};

View File

@ -0,0 +1,124 @@
* Analog Device AD5755 IIO Multi-Channel DAC Linux Driver
Required properties:
- compatible: Has to contain one of the following:
adi,ad5755
adi,ad5755-1
adi,ad5757
adi,ad5735
adi,ad5737
- reg: spi chip select number for the device
- spi-cpha or spi-cpol: is the only modes that is supported
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
See include/dt-bindings/iio/ad5755.h
- adi,ext-dc-dc-compenstation-resistor: boolean set if the hardware have an
external resistor and thereby bypasses
the internal compensation resistor.
- adi,dc-dc-phase:
Valid values for DC DC Phase control is:
0: All dc-to-dc converters clock on the same edge.
1: Channel A and Channel B clock on the same edge,
Channel C and Channel D clock on opposite edges.
2: Channel A and Channel C clock on the same edge,
Channel B and Channel D clock on opposite edges.
3: Channel A, Channel B, Channel C, and Channel D
clock 90 degrees out of phase from each other.
- adi,dc-dc-freq-hz:
Valid values for DC DC frequency is [Hz]:
250000
410000
650000
- adi,dc-dc-max-microvolt:
Valid values for the maximum allowed Vboost voltage supplied by
the dc-to-dc converter is:
23000000
24500000
27000000
29500000
Optional for every channel:
- adi,mode:
Valid values for DAC modes is:
0: 0 V to 5 V voltage range.
1: 0 V to 10 V voltage range.
2: Plus minus 5 V voltage range.
3: Plus minus 10 V voltage range.
4: 4 mA to 20 mA current range.
5: 0 mA to 20 mA current range.
6: 0 mA to 24 mA current range.
- adi,ext-current-sense-resistor: boolean set if the hardware a external
current sense resistor.
- adi,enable-voltage-overrange: boolean enable voltage overrange
- adi,slew: Array of slewrate settings should contain 3 fields:
1: Should be either 0 or 1 in order to enable or disable slewrate.
2: Slew rate settings:
Valid values for the slew rate update frequency:
64000
32000
16000
8000
4000
2000
1000
500
250
125
64
32
16
8
4
0
3: Slew step size:
Valid values for the step size LSBs:
1
2
4
16
32
64
128
256
Example:
dac@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "adi,ad5755";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpha;
adi,dc-dc-phase = <0>;
adi,dc-dc-freq-hz = <410000>;
adi,dc-dc-max-microvolt = <23000000>;
channel@0 {
reg = <0>;
adi,mode = <4>;
adi,ext-current-sense-resistor;
adi,slew = <0 64000 1>;
};
channel@1 {
reg = <1>;
adi,mode = <4>;
adi,ext-current-sense-resistor;
adi,slew = <0 64000 1>;
};
channel@2 {
reg = <2>;
adi,mode = <4>;
adi,ext-current-sense-resistor;
adi,slew = <0 64000 1>;
};
channel@3 {
reg = <3>;
adi,mode = <4>;
adi,ext-current-sense-resistor;
adi,slew = <0 64000 1>;
};
};

View File

@ -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

View File

@ -64,3 +64,4 @@ Pressure sensors:
- st,lps001wp-press
- st,lps25h-press
- st,lps331ap-press
- st,lps22hb-press

View File

@ -5788,7 +5788,9 @@ 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/
F: drivers/staging/iio/
F: include/linux/iio/
@ -10861,6 +10863,7 @@ STAGING - INDUSTRIAL IO
M: Jonathan Cameron <jic23@kernel.org>
L: linux-iio@vger.kernel.org
S: Odd Fixes
F: Documentation/devicetree/bindings/staging/iio/
F: drivers/staging/iio/
STAGING - LIRC (LINUX INFRARED REMOTE CONTROL) DRIVERS

View File

@ -46,6 +46,14 @@ config IIO_CONSUMERS_PER_TRIGGER
This value controls the maximum number of consumers that a
given trigger may handle. Default is 2.
config IIO_SW_DEVICE
tristate "Enable software IIO device support"
select IIO_CONFIGFS
help
Provides IIO core support for software devices. A software
device can be created via configfs or directly by a driver
using the API provided.
config IIO_SW_TRIGGER
tristate "Enable software triggers support"
select IIO_CONFIGFS

View File

@ -8,6 +8,7 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
obj-$(CONFIG_IIO_SW_DEVICE) += industrialio-sw-device.o
obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o

View File

@ -17,6 +17,16 @@ config BMA180
To compile this driver as a module, choose M here: the
module will be called bma180.
config BMA220
tristate "Bosch BMA220 3-Axis Accelerometer Driver"
depends on SPI
help
Say yes here to add support for the Bosch BMA220 triaxial
acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma220_spi.
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
select IIO_BUFFER
@ -136,13 +146,23 @@ config MMA7455_SPI
To compile this driver as a module, choose M here: the module
will be called mma7455_spi.
config MMA7660
tristate "Freescale MMA7660FC 3-Axis Accelerometer Driver"
depends on I2C
help
Say yes here to get support for the Freescale MMA7660FC 3-Axis
accelerometer.
Choosing M will build the driver as a module. If so, the module
will be called mma7660.
config MMA8452
tristate "Freescale MMA8452Q and similar Accelerometers Driver"
tristate "Freescale / NXP MMA8452Q and similar Accelerometers Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the following Freescale 3-axis
Say yes here to build support for the following Freescale / NXP 3-axis
accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC,
FXLS8471Q.

View File

@ -4,6 +4,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
@ -15,6 +16,8 @@ obj-$(CONFIG_MMA7455) += mma7455_core.o
obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o
obj-$(CONFIG_MMA7455_SPI) += mma7455_spi.o
obj-$(CONFIG_MMA7660) += mma7660.o
obj-$(CONFIG_MMA8452) += mma8452.o
obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o

View File

@ -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);

View File

@ -0,0 +1,338 @@
/**
* BMA220 Digital triaxial acceleration sensor driver
*
* Copyright (c) 2016, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define BMA220_REG_ID 0x00
#define BMA220_REG_ACCEL_X 0x02
#define BMA220_REG_ACCEL_Y 0x03
#define BMA220_REG_ACCEL_Z 0x04
#define BMA220_REG_RANGE 0x11
#define BMA220_REG_SUSPEND 0x18
#define BMA220_CHIP_ID 0xDD
#define BMA220_READ_MASK 0x80
#define BMA220_RANGE_MASK 0x03
#define BMA220_DATA_SHIFT 2
#define BMA220_SUSPEND_SLEEP 0xFF
#define BMA220_SUSPEND_WAKE 0x00
#define BMA220_DEVICE_NAME "bma220"
#define BMA220_SCALE_AVAILABLE "0.623 1.248 2.491 4.983"
#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
.realbits = 6, \
.storagebits = 8, \
.shift = BMA220_DATA_SHIFT, \
.endianness = IIO_CPU, \
}, \
}
enum bma220_axis {
AXIS_X,
AXIS_Y,
AXIS_Z,
};
static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE);
static struct attribute *bma220_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group bma220_attribute_group = {
.attrs = bma220_attributes,
};
static const int bma220_scale_table[][4] = {
{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}
};
struct bma220_data {
struct spi_device *spi_device;
struct mutex lock;
s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
u8 tx_buf[2] ____cacheline_aligned;
};
static const struct iio_chan_spec bma220_channels[] = {
BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X),
BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y),
BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static inline int bma220_read_reg(struct spi_device *spi, u8 reg)
{
return spi_w8r8(spi, reg | BMA220_READ_MASK);
}
static const unsigned long bma220_accel_scan_masks[] = {
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0
};
static irqreturn_t bma220_trigger_handler(int irq, void *p)
{
int ret;
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bma220_data *data = iio_priv(indio_dev);
struct spi_device *spi = data->spi_device;
mutex_lock(&data->lock);
data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
ARRAY_SIZE(bma220_channels) - 1);
if (ret < 0)
goto err;
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
pf->timestamp);
err:
mutex_unlock(&data->lock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int bma220_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
u8 range_idx;
struct bma220_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = bma220_read_reg(data->spi_device, chan->address);
if (ret < 0)
return -EINVAL;
*val = sign_extend32(ret >> BMA220_DATA_SHIFT, 5);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE);
if (ret < 0)
return ret;
range_idx = ret & BMA220_RANGE_MASK;
*val = bma220_scale_table[range_idx][0];
*val2 = bma220_scale_table[range_idx][1];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static int bma220_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int i;
int ret;
int index = -1;
struct bma220_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++)
if (val == bma220_scale_table[i][0] &&
val2 == bma220_scale_table[i][1]) {
index = i;
break;
}
if (index < 0)
return -EINVAL;
mutex_lock(&data->lock);
data->tx_buf[0] = BMA220_REG_RANGE;
data->tx_buf[1] = index;
ret = spi_write(data->spi_device, data->tx_buf,
sizeof(data->tx_buf));
if (ret < 0)
dev_err(&data->spi_device->dev,
"failed to set measurement range\n");
mutex_unlock(&data->lock);
return 0;
}
return -EINVAL;
}
static const struct iio_info bma220_info = {
.driver_module = THIS_MODULE,
.read_raw = bma220_read_raw,
.write_raw = bma220_write_raw,
.attrs = &bma220_attribute_group,
};
static int bma220_init(struct spi_device *spi)
{
int ret;
ret = bma220_read_reg(spi, BMA220_REG_ID);
if (ret != BMA220_CHIP_ID)
return -ENODEV;
/* Make sure the chip is powered on */
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret < 0)
return ret;
else if (ret == BMA220_SUSPEND_WAKE)
return bma220_read_reg(spi, BMA220_REG_SUSPEND);
return 0;
}
static int bma220_deinit(struct spi_device *spi)
{
int ret;
/* Make sure the chip is powered off */
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret < 0)
return ret;
else if (ret == BMA220_SUSPEND_SLEEP)
return bma220_read_reg(spi, BMA220_REG_SUSPEND);
return 0;
}
static int bma220_probe(struct spi_device *spi)
{
int ret;
struct iio_dev *indio_dev;
struct bma220_data *data;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&spi->dev, "iio allocation failed!\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
data->spi_device = spi;
spi_set_drvdata(spi, indio_dev);
mutex_init(&data->lock);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &bma220_info;
indio_dev->name = BMA220_DEVICE_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = bma220_channels;
indio_dev->num_channels = ARRAY_SIZE(bma220_channels);
indio_dev->available_scan_masks = bma220_accel_scan_masks;
ret = bma220_init(data->spi_device);
if (ret < 0)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bma220_trigger_handler, NULL);
if (ret < 0) {
dev_err(&spi->dev, "iio triggered buffer setup failed\n");
goto err_suspend;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&spi->dev, "iio_device_register failed\n");
iio_triggered_buffer_cleanup(indio_dev);
goto err_suspend;
}
return 0;
err_suspend:
return bma220_deinit(spi);
}
static int bma220_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return bma220_deinit(spi);
}
#ifdef CONFIG_PM_SLEEP
static int bma220_suspend(struct device *dev)
{
struct bma220_data *data =
iio_priv(spi_get_drvdata(to_spi_device(dev)));
/* The chip can be suspended/woken up by a simple register read. */
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
}
static int bma220_resume(struct device *dev)
{
struct bma220_data *data =
iio_priv(spi_get_drvdata(to_spi_device(dev)));
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
}
static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
#define BMA220_PM_OPS (&bma220_pm_ops)
#else
#define BMA220_PM_OPS NULL
#endif
static const struct spi_device_id bma220_spi_id[] = {
{"bma220", 0},
{}
};
static const struct acpi_device_id bma220_acpi_id[] = {
{"BMA0220", 0},
{}
};
MODULE_DEVICE_TABLE(spi, bma220_spi_id);
static struct spi_driver bma220_driver = {
.driver = {
.name = "bma220_spi",
.pm = BMA220_PM_OPS,
.acpi_match_table = ACPI_PTR(bma220_acpi_id),
},
.probe = bma220_probe,
.remove = bma220_remove,
.id_table = bma220_spi_id,
};
module_spi_driver(bma220_driver);
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
MODULE_DESCRIPTION("BMA220 acceleration sensor driver");
MODULE_LICENSE("GPL v2");

View File

@ -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) {

View File

@ -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);

View File

@ -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);

277
drivers/iio/accel/mma7660.c Normal file
View File

@ -0,0 +1,277 @@
/**
* Freescale MMA7660FC 3-Axis Accelerometer
*
* Copyright (c) 2016, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* IIO driver for Freescale MMA7660FC; 7-bit I2C address: 0x4c.
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define MMA7660_DRIVER_NAME "mma7660"
#define MMA7660_REG_XOUT 0x00
#define MMA7660_REG_YOUT 0x01
#define MMA7660_REG_ZOUT 0x02
#define MMA7660_REG_OUT_BIT_ALERT BIT(6)
#define MMA7660_REG_MODE 0x07
#define MMA7660_REG_MODE_BIT_MODE BIT(0)
#define MMA7660_REG_MODE_BIT_TON BIT(2)
#define MMA7660_I2C_READ_RETRIES 5
/*
* The accelerometer has one measurement range:
*
* -1.5g - +1.5g (6-bit, signed)
*
* scale = (1.5 + 1.5) * 9.81 / (2^6 - 1) = 0.467142857
*/
#define MMA7660_SCALE_AVAIL "0.467142857"
const int mma7660_nscale = 467142857;
#define MMA7660_CHANNEL(reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mma7660_channels[] = {
MMA7660_CHANNEL(MMA7660_REG_XOUT, X),
MMA7660_CHANNEL(MMA7660_REG_YOUT, Y),
MMA7660_CHANNEL(MMA7660_REG_ZOUT, Z),
};
enum mma7660_mode {
MMA7660_MODE_STANDBY,
MMA7660_MODE_ACTIVE
};
struct mma7660_data {
struct i2c_client *client;
struct mutex lock;
enum mma7660_mode mode;
};
static IIO_CONST_ATTR(in_accel_scale_available, MMA7660_SCALE_AVAIL);
static struct attribute *mma7660_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group mma7660_attribute_group = {
.attrs = mma7660_attributes
};
static int mma7660_set_mode(struct mma7660_data *data,
enum mma7660_mode mode)
{
int ret;
struct i2c_client *client = data->client;
if (mode == data->mode)
return 0;
ret = i2c_smbus_read_byte_data(client, MMA7660_REG_MODE);
if (ret < 0) {
dev_err(&client->dev, "failed to read sensor mode\n");
return ret;
}
if (mode == MMA7660_MODE_ACTIVE) {
ret &= ~MMA7660_REG_MODE_BIT_TON;
ret |= MMA7660_REG_MODE_BIT_MODE;
} else {
ret &= ~MMA7660_REG_MODE_BIT_TON;
ret &= ~MMA7660_REG_MODE_BIT_MODE;
}
ret = i2c_smbus_write_byte_data(client, MMA7660_REG_MODE, ret);
if (ret < 0) {
dev_err(&client->dev, "failed to change sensor mode\n");
return ret;
}
data->mode = mode;
return ret;
}
static int mma7660_read_accel(struct mma7660_data *data, u8 address)
{
int ret, retries = MMA7660_I2C_READ_RETRIES;
struct i2c_client *client = data->client;
/*
* Read data. If the Alert bit is set, the register was read at
* the same time as the device was attempting to update the content.
* The solution is to read the register again. Do this only
* MMA7660_I2C_READ_RETRIES times to avoid spending too much time
* in the kernel.
*/
do {
ret = i2c_smbus_read_byte_data(client, address);
if (ret < 0) {
dev_err(&client->dev, "register read failed\n");
return ret;
}
} while (retries-- > 0 && ret & MMA7660_REG_OUT_BIT_ALERT);
if (ret & MMA7660_REG_OUT_BIT_ALERT) {
dev_err(&client->dev, "all register read retries failed\n");
return -ETIMEDOUT;
}
return ret;
}
static int mma7660_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mma7660_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
ret = mma7660_read_accel(data, chan->address);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 5);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = mma7660_nscale;
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
return -EINVAL;
}
static const struct iio_info mma7660_info = {
.driver_module = THIS_MODULE,
.read_raw = mma7660_read_raw,
.attrs = &mma7660_attribute_group,
};
static int mma7660_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct mma7660_data *data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&client->dev, "iio allocation failed!\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
data->client = client;
i2c_set_clientdata(client, indio_dev);
mutex_init(&data->lock);
data->mode = MMA7660_MODE_STANDBY;
indio_dev->dev.parent = &client->dev;
indio_dev->info = &mma7660_info;
indio_dev->name = MMA7660_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mma7660_channels;
indio_dev->num_channels = ARRAY_SIZE(mma7660_channels);
ret = mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
mma7660_set_mode(data, MMA7660_MODE_STANDBY);
}
return ret;
}
static int mma7660_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
return mma7660_set_mode(iio_priv(indio_dev), MMA7660_MODE_STANDBY);
}
#ifdef CONFIG_PM_SLEEP
static int mma7660_suspend(struct device *dev)
{
struct mma7660_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return mma7660_set_mode(data, MMA7660_MODE_STANDBY);
}
static int mma7660_resume(struct device *dev)
{
struct mma7660_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return mma7660_set_mode(data, MMA7660_MODE_ACTIVE);
}
static SIMPLE_DEV_PM_OPS(mma7660_pm_ops, mma7660_suspend, mma7660_resume);
#define MMA7660_PM_OPS (&mma7660_pm_ops)
#else
#define MMA7660_PM_OPS NULL
#endif
static const struct i2c_device_id mma7660_i2c_id[] = {
{"mma7660", 0},
{}
};
static const struct acpi_device_id mma7660_acpi_id[] = {
{"MMA7660", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, mma7660_acpi_id);
static struct i2c_driver mma7660_driver = {
.driver = {
.name = "mma7660",
.pm = MMA7660_PM_OPS,
.acpi_match_table = ACPI_PTR(mma7660_acpi_id),
},
.probe = mma7660_probe,
.remove = mma7660_remove,
.id_table = mma7660_i2c_id,
};
module_i2c_driver(mma7660_driver);
MODULE_AUTHOR("Constantin Musca <constantin.musca@intel.com>");
MODULE_DESCRIPTION("Freescale MMA7660FC 3-Axis Accelerometer driver");
MODULE_LICENSE("GPL v2");

View File

@ -1,22 +1,22 @@
/*
* mma8452.c - Support for following Freescale 3-axis accelerometers:
* mma8452.c - Support for following Freescale / NXP 3-axis accelerometers:
*
* MMA8451Q (14 bit)
* MMA8452Q (12 bit)
* MMA8453Q (10 bit)
* MMA8652FC (12 bit)
* MMA8653FC (10 bit)
* FXLS8471Q (14 bit)
* device name digital output 7-bit I2C slave address (pin selectable)
* ---------------------------------------------------------------------
* MMA8451Q 14 bit 0x1c / 0x1d
* MMA8452Q 12 bit 0x1c / 0x1d
* MMA8453Q 10 bit 0x1c / 0x1d
* MMA8652FC 12 bit 0x1d
* MMA8653FC 10 bit 0x1d
* FXLS8471Q 14 bit 0x1e / 0x1d / 0x1c / 0x1f
*
* Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
* Copyright 2015 Martin Kepplinger <martink@posteo.de>
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
*
* TODO: orientation events
*/
@ -76,6 +76,8 @@
#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
#define MMA8452_CTRL_REG2 0x2b
#define MMA8452_CTRL_REG2_RST BIT(6)
#define MMA8452_CTRL_REG2_MODS_SHIFT 3
#define MMA8452_CTRL_REG2_MODS_MASK 0x1b
#define MMA8452_CTRL_REG4 0x2d
#define MMA8452_CTRL_REG5 0x2e
#define MMA8452_OFF_X 0x2f
@ -106,7 +108,7 @@ struct mma8452_data {
};
/**
* struct mma_chip_info - chip specific data for Freescale's accelerometers
* struct mma_chip_info - chip specific data
* @chip_id: WHO_AM_I register's value
* @channels: struct iio_chan_spec matching the device's
* capabilities
@ -257,20 +259,17 @@ static const int mma8452_samp_freq[8][2] = {
{6, 250000}, {1, 560000}
};
/* Datasheet table 35 (step time vs sample frequency) */
static const int mma8452_transient_time_step_us[8] = {
1250,
2500,
5000,
10000,
20000,
20000,
20000,
20000
/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
static const int mma8452_transient_time_step_us[4][8] = {
{ 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */
{ 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */
{ 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/
{ 1250, 2500, 5000, 10000, 20000, 80000, 160000, 160000 } /* l p */
};
/* Datasheet table 18 (normal mode) */
static const int mma8452_hp_filter_cutoff[8][4][2] = {
/* Datasheet table "High-Pass Filter Cutoff Options" */
static const int mma8452_hp_filter_cutoff[4][8][4][2] = {
{ /* normal */
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 800 Hz sample */
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} }, /* 400 Hz sample */
{ {8, 0}, {4, 0}, {2, 0}, {1, 0} }, /* 200 Hz sample */
@ -279,8 +278,61 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = {
{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 12.5 Hz sample */
{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} }, /* 6.25 Hz sample */
{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} } /* 1.56 Hz sample */
},
{ /* low noise low power */
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },
{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} },
{ {0, 500000}, {0, 250000}, {0, 125000}, {0, 063000} }
},
{ /* high resolution */
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} }
},
{ /* low power */
{ {16, 0}, {8, 0}, {4, 0}, {2, 0} },
{ {8, 0}, {4, 0}, {2, 0}, {1, 0} },
{ {4, 0}, {2, 0}, {1, 0}, {0, 500000} },
{ {2, 0}, {1, 0}, {0, 500000}, {0, 250000} },
{ {1, 0}, {0, 500000}, {0, 250000}, {0, 125000} },
{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} },
{ {0, 250000}, {0, 125000}, {0, 063000}, {0, 031000} }
}
};
/* Datasheet table "MODS Oversampling modes averaging values at each ODR" */
static const u16 mma8452_os_ratio[4][8] = {
/* 800 Hz, 400 Hz, ... , 1.56 Hz */
{ 2, 4, 4, 4, 4, 16, 32, 128 }, /* normal */
{ 2, 4, 4, 4, 4, 4, 8, 32 }, /* low power low noise */
{ 2, 4, 8, 16, 32, 128, 256, 1024 }, /* high resolution */
{ 2, 2, 2, 2, 2, 2, 4, 16 } /* low power */
};
static int mma8452_get_power_mode(struct mma8452_data *data)
{
int reg;
reg = i2c_smbus_read_byte_data(data->client,
MMA8452_CTRL_REG2);
if (reg < 0)
return reg;
return ((reg & MMA8452_CTRL_REG2_MODS_MASK) >>
MMA8452_CTRL_REG2_MODS_SHIFT);
}
static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -306,10 +358,39 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct mma8452_data *data = iio_priv(indio_dev);
int i = mma8452_get_odr_index(data);
int i, j;
return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[i],
ARRAY_SIZE(mma8452_hp_filter_cutoff[0]));
i = mma8452_get_odr_index(data);
j = mma8452_get_power_mode(data);
if (j < 0)
return j;
return mma8452_show_int_plus_micros(buf, mma8452_hp_filter_cutoff[j][i],
ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]));
}
static ssize_t mma8452_show_os_ratio_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct mma8452_data *data = iio_priv(indio_dev);
int i = mma8452_get_odr_index(data);
int j;
u16 val = 0;
size_t len = 0;
for (j = 0; j < ARRAY_SIZE(mma8452_os_ratio); j++) {
if (val == mma8452_os_ratio[j][i])
continue;
val = mma8452_os_ratio[j][i];
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", val);
}
buf[len - 1] = '\n';
return len;
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
@ -317,6 +398,8 @@ static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
mma8452_show_scale_avail, NULL, 0);
static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
static IIO_DEVICE_ATTR(in_accel_oversampling_ratio_available, S_IRUGO,
mma8452_show_os_ratio_avail, NULL, 0);
static int mma8452_get_samp_freq_index(struct mma8452_data *data,
int val, int val2)
@ -335,24 +418,33 @@ static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
static int mma8452_get_hp_filter_index(struct mma8452_data *data,
int val, int val2)
{
int i = mma8452_get_odr_index(data);
int i, j;
return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
i = mma8452_get_odr_index(data);
j = mma8452_get_power_mode(data);
if (j < 0)
return j;
return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[j][i],
ARRAY_SIZE(mma8452_hp_filter_cutoff[0][0]), val, val2);
}
static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
{
int i, ret;
int j, i, ret;
ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF);
if (ret < 0)
return ret;
i = mma8452_get_odr_index(data);
j = mma8452_get_power_mode(data);
if (j < 0)
return j;
ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
*hz = mma8452_hp_filter_cutoff[i][ret][0];
*uHz = mma8452_hp_filter_cutoff[i][ret][1];
*hz = mma8452_hp_filter_cutoff[j][i][ret][0];
*uHz = mma8452_hp_filter_cutoff[j][i][ret][1];
return 0;
}
@ -414,6 +506,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
}
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = mma8452_get_power_mode(data);
if (ret < 0)
return ret;
i = mma8452_get_odr_index(data);
*val = mma8452_os_ratio[ret][i];
return IIO_VAL_INT;
}
return -EINVAL;
@ -480,6 +581,21 @@ fail:
return ret;
}
static int mma8452_set_power_mode(struct mma8452_data *data, u8 mode)
{
int reg;
reg = i2c_smbus_read_byte_data(data->client,
MMA8452_CTRL_REG2);
if (reg < 0)
return reg;
reg &= ~MMA8452_CTRL_REG2_MODS_MASK;
reg |= mode << MMA8452_CTRL_REG2_MODS_SHIFT;
return mma8452_change_config(data, MMA8452_CTRL_REG2, reg);
}
/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
{
@ -518,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,
@ -597,6 +709,14 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
return mma8452_change_config(data, MMA8452_DATA_CFG,
data->data_cfg);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = mma8452_get_odr_index(data);
for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) {
if (mma8452_os_ratio[i][ret] == val)
return mma8452_set_power_mode(data, i);
}
default:
return -EINVAL;
}
@ -610,7 +730,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
int *val, int *val2)
{
struct mma8452_data *data = iio_priv(indio_dev);
int ret, us;
int ret, us, power_mode;
switch (info) {
case IIO_EV_INFO_VALUE:
@ -629,7 +749,11 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
us = ret * mma8452_transient_time_step_us[
power_mode = mma8452_get_power_mode(data);
if (power_mode < 0)
return power_mode;
us = ret * mma8452_transient_time_step_us[power_mode][
mma8452_get_odr_index(data)];
*val = us / USEC_PER_SEC;
*val2 = us % USEC_PER_SEC;
@ -677,8 +801,12 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
val);
case IIO_EV_INFO_PERIOD:
ret = mma8452_get_power_mode(data);
if (ret < 0)
return ret;
steps = (val * USEC_PER_SEC + val2) /
mma8452_transient_time_step_us[
mma8452_transient_time_step_us[ret][
mma8452_get_odr_index(data)];
if (steps < 0 || steps > 0xff)
@ -785,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);
@ -865,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);
@ -978,7 +1106,8 @@ static struct attribute_group mma8452_event_attribute_group = {
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
@ -998,7 +1127,8 @@ static struct attribute_group mma8452_event_attribute_group = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE), \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
@ -1171,6 +1301,7 @@ static struct attribute *mma8452_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
&iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_oversampling_ratio_available.dev_attr.attr,
NULL
};
@ -1444,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;
@ -1558,5 +1689,5 @@ static struct i2c_driver mma8452_driver = {
module_i2c_driver(mma8452_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("Freescale MMA8452 accelerometer driver");
MODULE_DESCRIPTION("Freescale / NXP MMA8452 accelerometer driver");
MODULE_LICENSE("GPL");

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,
@ -758,13 +822,15 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
indio_dev->info = &accel_info;
mutex_init(&adata->tb.buf_lock);
st_sensors_power_enable(indio_dev);
err = st_sensors_power_enable(indio_dev);
if (err)
return err;
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_accel_sensors_settings),
st_accel_sensors_settings);
if (err < 0)
return err;
goto st_accel_power_off;
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
adata->multiread_bit = adata->sensor_settings->multi_read_bit;
@ -781,11 +847,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
if (err < 0)
return err;
goto st_accel_power_off;
err = st_accel_allocate_ring(indio_dev);
if (err < 0)
return err;
goto st_accel_power_off;
if (irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@ -808,6 +874,8 @@ st_accel_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_accel_probe_trigger_error:
st_accel_deallocate_ring(indio_dev);
st_accel_power_off:
st_sensors_power_disable(indio_dev);
return err;
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -154,12 +154,11 @@ static int ad7266_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
ret = ad7266_read_single(st, val, chan->address);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ad7266_read_single(st, val, chan->address);
iio_device_release_direct_mode(indio_dev);
*val = (*val >> 2) & 0xfff;
if (chan->scan_type.sign == 's')
@ -441,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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
@ -106,12 +106,11 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7476_scan_direct(st);
mutex_unlock(&indio_dev->mlock);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ad7476_scan_direct(st);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
@ -228,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;

View File

@ -272,30 +272,22 @@ static ssize_t ad7791_write_frequency(struct device *dev,
struct ad7791_state *st = iio_priv(indio_dev);
int i, ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
mutex_unlock(&indio_dev->mlock);
ret = -EINVAL;
for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) {
if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) {
mutex_lock(&indio_dev->mlock);
st->filter &= ~AD7791_FILTER_RATE_MASK;
st->filter |= i;
ad_sd_write_reg(&st->sd, AD7791_REG_FILTER,
sizeof(st->filter), st->filter);
mutex_unlock(&indio_dev->mlock);
ret = 0;
for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++)
if (sysfs_streq(ad7791_sample_freq_avail[i], buf))
break;
}
}
if (i == ARRAY_SIZE(ad7791_sample_freq_avail))
return -EINVAL;
return ret ? ret : len;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
st->filter &= ~AD7791_FILTER_RATE_MASK;
st->filter |= i;
ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, sizeof(st->filter),
st->filter);
iio_device_release_direct_mode(indio_dev);
return len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@ -383,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;

View File

@ -369,13 +369,6 @@ static ssize_t ad7793_write_frequency(struct device *dev,
long lval;
int i, ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
mutex_unlock(&indio_dev->mlock);
ret = kstrtol(buf, 10, &lval);
if (ret)
return ret;
@ -383,20 +376,21 @@ static ssize_t ad7793_write_frequency(struct device *dev,
if (lval == 0)
return -EINVAL;
ret = -EINVAL;
for (i = 0; i < 16; i++)
if (lval == st->chip_info->sample_freq_avail[i]) {
mutex_lock(&indio_dev->mlock);
st->mode &= ~AD7793_MODE_RATE(-1);
st->mode |= AD7793_MODE_RATE(i);
ad_sd_write_reg(&st->sd, AD7793_REG_MODE,
sizeof(st->mode), st->mode);
mutex_unlock(&indio_dev->mlock);
ret = 0;
}
if (lval == st->chip_info->sample_freq_avail[i])
break;
if (i == 16)
return -EINVAL;
return ret ? ret : len;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
st->mode &= ~AD7793_MODE_RATE(-1);
st->mode |= AD7793_MODE_RATE(i);
ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), st->mode);
iio_device_release_direct_mode(indio_dev);
return len;
}
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
@ -790,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;

View File

@ -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);
@ -156,12 +156,11 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7887_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ad7887_scan_direct(st, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
@ -265,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;

View File

@ -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);
@ -233,12 +233,11 @@ static int ad7923_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad7923_scan_direct(st, chan->address);
mutex_unlock(&indio_dev->mlock);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ad7923_scan_direct(st, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
@ -289,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;

View File

@ -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);
@ -282,12 +282,11 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = ad799x_scan_direct(st, chan->scan_index);
mutex_unlock(&indio_dev->mlock);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ad799x_scan_direct(st, chan->scan_index);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
@ -395,11 +394,9 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto done;
}
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
if (state)
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
@ -412,10 +409,7 @@ static int ad799x_write_event_config(struct iio_dev *indio_dev,
st->config &= ~AD7998_ALERT_EN;
ret = ad799x_write_config(st, st->config);
done:
mutex_unlock(&indio_dev->mlock);
iio_device_release_direct_mode(indio_dev);
return ret;
}
@ -508,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:
@ -812,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;

View 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");

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -373,13 +373,6 @@ static u32 mxs_lradc_plate_mask(struct mxs_lradc *lradc)
return LRADC_CTRL0_MX28_PLATE_MASK;
}
static u32 mxs_lradc_irq_en_mask(struct mxs_lradc *lradc)
{
if (lradc->soc == IMX23_LRADC)
return LRADC_CTRL1_MX23_LRADC_IRQ_EN_MASK;
return LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK;
}
static u32 mxs_lradc_irq_mask(struct mxs_lradc *lradc)
{
if (lradc->soc == IMX23_LRADC)
@ -1120,18 +1113,16 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
{
struct input_dev *input;
struct device *dev = lradc->dev;
int ret;
if (!lradc->use_touchscreen)
return 0;
input = input_allocate_device();
input = devm_input_allocate_device(dev);
if (!input)
return -ENOMEM;
input->name = DRIVER_NAME;
input->id.bustype = BUS_HOST;
input->dev.parent = dev;
input->open = mxs_lradc_ts_open;
input->close = mxs_lradc_ts_close;
@ -1146,20 +1137,8 @@ static int mxs_lradc_ts_register(struct mxs_lradc *lradc)
lradc->ts_input = input;
input_set_drvdata(input, lradc);
ret = input_register_device(input);
if (ret)
input_free_device(lradc->ts_input);
return ret;
}
static void mxs_lradc_ts_unregister(struct mxs_lradc *lradc)
{
if (!lradc->use_touchscreen)
return;
mxs_lradc_disable_ts(lradc);
input_unregister_device(lradc->ts_input);
return input_register_device(input);
}
/*
@ -1510,7 +1489,9 @@ static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
{
int i;
mxs_lradc_reg_clear(lradc, mxs_lradc_irq_en_mask(lradc), LRADC_CTRL1);
mxs_lradc_reg_clear(lradc,
lradc->buffer_vchans << LRADC_CTRL1_LRADC_IRQ_EN_OFFSET,
LRADC_CTRL1);
for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(i));
@ -1721,13 +1702,11 @@ static int mxs_lradc_probe(struct platform_device *pdev)
ret = iio_device_register(iio);
if (ret) {
dev_err(dev, "Failed to register IIO device\n");
goto err_ts;
return ret;
}
return 0;
err_ts:
mxs_lradc_ts_unregister(lradc);
err_ts_register:
mxs_lradc_hw_stop(lradc);
err_dev:
@ -1745,7 +1724,6 @@ static int mxs_lradc_remove(struct platform_device *pdev)
struct mxs_lradc *lradc = iio_priv(iio);
iio_device_unregister(iio);
mxs_lradc_ts_unregister(lradc);
mxs_lradc_hw_stop(lradc);
mxs_lradc_trigger_remove(iio);
iio_triggered_buffer_cleanup(iio);

View File

@ -79,10 +79,29 @@ static const struct iio_chan_spec nau7802_chan_array[] = {
static const u16 nau7802_sample_freq_avail[] = {10, 20, 40, 80,
10, 10, 10, 320};
static ssize_t nau7802_show_scales(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nau7802_state *st = iio_priv(dev_to_iio_dev(dev));
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%09d ",
st->scale_avail[i]);
buf[len-1] = '\n';
return len;
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 40 80 320");
static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO, nau7802_show_scales,
NULL, 0);
static struct attribute *nau7802_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
NULL
};
@ -414,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;

View File

@ -22,6 +22,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@ -138,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;
@ -149,12 +151,24 @@ static int adc081c_probe(struct i2c_client *client,
{
struct iio_dev *iio;
struct adc081c *adc;
struct adcxx1c_model *model = &adcxx1c_models[id->driver_data];
struct adcxx1c_model *model;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
if (ACPI_COMPANION(&client->dev)) {
const struct acpi_device_id *ad_id;
ad_id = acpi_match_device(client->dev.driver->acpi_match_table,
&client->dev);
if (!ad_id)
return -ENODEV;
model = &adcxx1c_models[ad_id->driver_data];
} else {
model = &adcxx1c_models[id->driver_data];
}
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
return -ENOMEM;
@ -172,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;
@ -231,10 +246,21 @@ static const struct of_device_id adc081c_of_match[] = {
MODULE_DEVICE_TABLE(of, adc081c_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id adc081c_acpi_match[] = {
{ "ADC081C", ADC081C },
{ "ADC101C", ADC101C },
{ "ADC121C", ADC121C },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match);
#endif
static struct i2c_driver adc081c_driver = {
.driver = {
.name = "adc081c",
.of_match_table = of_match_ptr(adc081c_of_match),
.acpi_match_table = ACPI_PTR(adc081c_acpi_match),
},
.probe = adc081c_probe,
.remove = adc081c_remove,

View File

@ -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;

View File

@ -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;

View File

@ -55,6 +55,11 @@
#define ADS1015_DEFAULT_DATA_RATE 4
#define ADS1015_DEFAULT_CHAN 0
enum {
ADS1015,
ADS1115,
};
enum ads1015_channels {
ADS1015_AIN0_AIN1 = 0,
ADS1015_AIN0_AIN3,
@ -71,6 +76,10 @@ static const unsigned int ads1015_data_rate[] = {
128, 250, 490, 920, 1600, 2400, 3300, 3300
};
static const unsigned int ads1115_data_rate[] = {
8, 16, 32, 64, 128, 250, 475, 860
};
static const struct {
int scale;
int uscale;
@ -101,6 +110,7 @@ static const struct {
.shift = 4, \
.endianness = IIO_CPU, \
}, \
.datasheet_name = "AIN"#_chan, \
}
#define ADS1015_V_DIFF_CHAN(_chan, _chan2, _addr) { \
@ -121,6 +131,45 @@ static const struct {
.shift = 4, \
.endianness = IIO_CPU, \
}, \
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
}
#define ADS1115_V_CHAN(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.address = _addr, \
.channel = _chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = _addr, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
.datasheet_name = "AIN"#_chan, \
}
#define ADS1115_V_DIFF_CHAN(_chan, _chan2, _addr) { \
.type = IIO_VOLTAGE, \
.differential = 1, \
.indexed = 1, \
.address = _addr, \
.channel = _chan, \
.channel2 = _chan2, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = _addr, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
}
struct ads1015_data {
@ -131,6 +180,8 @@ struct ads1015_data {
*/
struct mutex lock;
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
unsigned int *data_rate;
};
static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg)
@ -157,6 +208,18 @@ static const struct iio_chan_spec ads1015_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
};
static const struct iio_chan_spec ads1115_channels[] = {
ADS1115_V_DIFF_CHAN(0, 1, ADS1015_AIN0_AIN1),
ADS1115_V_DIFF_CHAN(0, 3, ADS1015_AIN0_AIN3),
ADS1115_V_DIFF_CHAN(1, 3, ADS1015_AIN1_AIN3),
ADS1115_V_DIFF_CHAN(2, 3, ADS1015_AIN2_AIN3),
ADS1115_V_CHAN(0, ADS1015_AIN0),
ADS1115_V_CHAN(1, ADS1015_AIN1),
ADS1115_V_CHAN(2, ADS1015_AIN2),
ADS1115_V_CHAN(3, ADS1015_AIN3),
IIO_CHAN_SOFT_TIMESTAMP(ADS1015_TIMESTAMP),
};
static int ads1015_set_power_state(struct ads1015_data *data, bool on)
{
int ret;
@ -196,7 +259,7 @@ int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
return ret;
if (change) {
conv_time = DIV_ROUND_UP(USEC_PER_SEC, ads1015_data_rate[dr]);
conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
usleep_range(conv_time, conv_time + 1);
}
@ -225,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);
@ -263,7 +327,7 @@ static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
int i, ret, rindex = -1;
for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++)
if (ads1015_data_rate[i] == rate) {
if (data->data_rate[i] == rate) {
rindex = i;
break;
}
@ -291,7 +355,9 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
mutex_lock(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_RAW: {
int shift = chan->scan_type.shift;
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
break;
@ -307,8 +373,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
break;
}
/* 12 bit res, D0 is bit 4 in conversion register */
*val = sign_extend32(*val >> 4, 11);
*val = sign_extend32(*val >> shift, 15 - shift);
ret = ads1015_set_power_state(data, false);
if (ret < 0)
@ -316,6 +381,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
ret = IIO_VAL_INT;
break;
}
case IIO_CHAN_INFO_SCALE:
idx = data->channel_data[chan->address].pga;
*val = ads1015_scale[idx].scale;
@ -324,7 +390,7 @@ static int ads1015_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_SAMP_FREQ:
idx = data->channel_data[chan->address].data_rate;
*val = ads1015_data_rate[idx];
*val = data->data_rate[idx];
ret = IIO_VAL_INT;
break;
default:
@ -380,12 +446,15 @@ static const struct iio_buffer_setup_ops ads1015_buffer_setup_ops = {
};
static IIO_CONST_ATTR(scale_available, "3 2 1 0.5 0.25 0.125");
static IIO_CONST_ATTR(sampling_frequency_available,
"128 250 490 920 1600 2400 3300");
static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available,
sampling_frequency_available, "128 250 490 920 1600 2400 3300");
static IIO_CONST_ATTR_NAMED(ads1115_sampling_frequency_available,
sampling_frequency_available, "8 16 32 64 128 250 475 860");
static struct attribute *ads1015_attributes[] = {
&iio_const_attr_scale_available.dev_attr.attr,
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr,
NULL,
};
@ -393,11 +462,28 @@ static const struct attribute_group ads1015_attribute_group = {
.attrs = ads1015_attributes,
};
static const struct iio_info ads1015_info = {
static struct attribute *ads1115_attributes[] = {
&iio_const_attr_scale_available.dev_attr.attr,
&iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ads1115_attribute_group = {
.attrs = ads1115_attributes,
};
static struct iio_info ads1015_info = {
.driver_module = THIS_MODULE,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
.attrs = &ads1015_attribute_group,
.attrs = &ads1015_attribute_group,
};
static struct iio_info ads1115_info = {
.driver_module = THIS_MODULE,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
.attrs = &ads1115_attribute_group,
};
#ifdef CONFIG_OF
@ -500,12 +586,25 @@ static int ads1015_probe(struct i2c_client *client,
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &ads1015_info;
indio_dev->dev.of_node = client->dev.of_node;
indio_dev->name = ADS1015_DRV_NAME;
indio_dev->channels = ads1015_channels;
indio_dev->num_channels = ARRAY_SIZE(ads1015_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
switch (id->driver_data) {
case ADS1015:
indio_dev->channels = ads1015_channels;
indio_dev->num_channels = ARRAY_SIZE(ads1015_channels);
indio_dev->info = &ads1015_info;
data->data_rate = (unsigned int *) &ads1015_data_rate;
break;
case ADS1115:
indio_dev->channels = ads1115_channels;
indio_dev->num_channels = ARRAY_SIZE(ads1115_channels);
indio_dev->info = &ads1115_info;
data->data_rate = (unsigned int *) &ads1115_data_rate;
break;
}
/* we need to keep this ABI the same as used by hwmon ADS1015 driver */
ads1015_get_channels_config(client);
@ -590,7 +689,8 @@ static const struct dev_pm_ops ads1015_pm_ops = {
};
static const struct i2c_device_id ads1015_id[] = {
{"ads1015", 0},
{"ads1015", ADS1015},
{"ads1115", ADS1115},
{}
};
MODULE_DEVICE_TABLE(i2c, ads1015_id);

View File

@ -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;

View File

@ -326,8 +326,7 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
int i;
indio_dev->num_channels = channels;
chan_array = kcalloc(channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
chan_array = kcalloc(channels, sizeof(*chan_array), GFP_KERNEL);
if (chan_array == NULL)
return -ENOMEM;
@ -467,8 +466,7 @@ static int tiadc_probe(struct platform_device *pdev)
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct tiadc_device));
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*indio_dev));
if (indio_dev == NULL) {
dev_err(&pdev->dev, "failed to allocate iio device\n");
return -ENOMEM;
@ -531,8 +529,7 @@ static int tiadc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int tiadc_suspend(struct device *dev)
static int __maybe_unused tiadc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
@ -550,7 +547,7 @@ static int tiadc_suspend(struct device *dev)
return 0;
}
static int tiadc_resume(struct device *dev)
static int __maybe_unused tiadc_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
@ -567,14 +564,7 @@ static int tiadc_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops tiadc_pm_ops = {
.suspend = tiadc_suspend,
.resume = tiadc_resume,
};
#define TIADC_PM_OPS (&tiadc_pm_ops)
#else
#define TIADC_PM_OPS NULL
#endif
static SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume);
static const struct of_device_id ti_adc_dt_ids[] = {
{ .compatible = "ti,am3359-adc", },
@ -585,7 +575,7 @@ MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
static struct platform_driver tiadc_driver = {
.driver = {
.name = "TI-am335x-adc",
.pm = TIADC_PM_OPS,
.pm = &tiadc_pm_ops,
.of_match_table = ti_adc_dt_ids,
},
.probe = tiadc_probe,

View File

@ -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);

View File

@ -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));
}
}

View File

@ -305,7 +305,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
queue->fileio.active_block = NULL;
spin_lock_irq(&queue->list_lock);
for (i = 0; i < 2; i++) {
for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
block = queue->fileio.blocks[i];
/* If we can't re-use it free it */
@ -323,7 +323,7 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
INIT_LIST_HEAD(&queue->incoming);
for (i = 0; i < 2; i++) {
for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
if (queue->fileio.blocks[i]) {
block = queue->fileio.blocks[i];
if (block->state == IIO_BLOCK_STATE_DEAD) {

View File

@ -5,15 +5,17 @@
menu "Chemical Sensors"
config ATLAS_PH_SENSOR
tristate "Atlas Scientific OEM pH-SM sensor"
tristate "Atlas Scientific OEM SM sensors"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IRQ_WORK
help
Say Y here to build I2C interface support for the Atlas
Scientific OEM pH-SM sensor.
Say Y here to build I2C interface support for the following
Atlas Scientific OEM SM sensors:
* pH SM sensor
* EC SM sensor
To compile this driver as module, choose M here: the
module will be called atlas-ph-sensor.

View File

@ -24,6 +24,7 @@
#include <linux/irq_work.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
@ -43,29 +44,50 @@
#define ATLAS_REG_PWR_CONTROL 0x06
#define ATLAS_REG_CALIB_STATUS 0x0d
#define ATLAS_REG_CALIB_STATUS_MASK 0x07
#define ATLAS_REG_CALIB_STATUS_LOW BIT(0)
#define ATLAS_REG_CALIB_STATUS_MID BIT(1)
#define ATLAS_REG_CALIB_STATUS_HIGH BIT(2)
#define ATLAS_REG_PH_CALIB_STATUS 0x0d
#define ATLAS_REG_PH_CALIB_STATUS_MASK 0x07
#define ATLAS_REG_PH_CALIB_STATUS_LOW BIT(0)
#define ATLAS_REG_PH_CALIB_STATUS_MID BIT(1)
#define ATLAS_REG_PH_CALIB_STATUS_HIGH BIT(2)
#define ATLAS_REG_TEMP_DATA 0x0e
#define ATLAS_REG_EC_CALIB_STATUS 0x0f
#define ATLAS_REG_EC_CALIB_STATUS_MASK 0x0f
#define ATLAS_REG_EC_CALIB_STATUS_DRY BIT(0)
#define ATLAS_REG_EC_CALIB_STATUS_SINGLE BIT(1)
#define ATLAS_REG_EC_CALIB_STATUS_LOW BIT(2)
#define ATLAS_REG_EC_CALIB_STATUS_HIGH BIT(3)
#define ATLAS_REG_PH_TEMP_DATA 0x0e
#define ATLAS_REG_PH_DATA 0x16
#define ATLAS_REG_EC_PROBE 0x08
#define ATLAS_REG_EC_TEMP_DATA 0x10
#define ATLAS_REG_EC_DATA 0x18
#define ATLAS_REG_TDS_DATA 0x1c
#define ATLAS_REG_PSS_DATA 0x20
#define ATLAS_PH_INT_TIME_IN_US 450000
#define ATLAS_EC_INT_TIME_IN_US 650000
enum {
ATLAS_PH_SM,
ATLAS_EC_SM,
};
struct atlas_data {
struct i2c_client *client;
struct iio_trigger *trig;
struct atlas_device *chip;
struct regmap *regmap;
struct irq_work work;
__be32 buffer[4]; /* 32-bit pH data + 32-bit pad + 64-bit timestamp */
__be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
};
static const struct regmap_range atlas_volatile_ranges[] = {
regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4),
};
static const struct regmap_access_table atlas_volatile_table = {
@ -80,13 +102,14 @@ static const struct regmap_config atlas_regmap_config = {
.val_bits = 8,
.volatile_table = &atlas_volatile_table,
.max_register = ATLAS_REG_PH_DATA + 4,
.max_register = ATLAS_REG_PSS_DATA + 4,
.cache_type = REGCACHE_RBTREE,
};
static const struct iio_chan_spec atlas_channels[] = {
static const struct iio_chan_spec atlas_ph_channels[] = {
{
.type = IIO_PH,
.address = ATLAS_REG_PH_DATA,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
@ -100,7 +123,7 @@ static const struct iio_chan_spec atlas_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
{
.type = IIO_TEMP,
.address = ATLAS_REG_TEMP_DATA,
.address = ATLAS_REG_PH_TEMP_DATA,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.output = 1,
@ -108,6 +131,142 @@ static const struct iio_chan_spec atlas_channels[] = {
},
};
#define ATLAS_EC_CHANNEL(_idx, _addr) \
{\
.type = IIO_CONCENTRATION, \
.indexed = 1, \
.channel = _idx, \
.address = _addr, \
.info_mask_separate = \
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = _idx + 1, \
.scan_type = { \
.sign = 'u', \
.realbits = 32, \
.storagebits = 32, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec atlas_ec_channels[] = {
{
.type = IIO_ELECTRICALCONDUCTIVITY,
.address = ATLAS_REG_EC_DATA,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_BE,
},
},
ATLAS_EC_CHANNEL(0, ATLAS_REG_TDS_DATA),
ATLAS_EC_CHANNEL(1, ATLAS_REG_PSS_DATA),
IIO_CHAN_SOFT_TIMESTAMP(3),
{
.type = IIO_TEMP,
.address = ATLAS_REG_EC_TEMP_DATA,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.output = 1,
.scan_index = -1
},
};
static int atlas_check_ph_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
int ret;
unsigned int val;
ret = regmap_read(data->regmap, ATLAS_REG_PH_CALIB_STATUS, &val);
if (ret)
return ret;
if (!(val & ATLAS_REG_PH_CALIB_STATUS_MASK)) {
dev_warn(dev, "device has not been calibrated\n");
return 0;
}
if (!(val & ATLAS_REG_PH_CALIB_STATUS_LOW))
dev_warn(dev, "device missing low point calibration\n");
if (!(val & ATLAS_REG_PH_CALIB_STATUS_MID))
dev_warn(dev, "device missing mid point calibration\n");
if (!(val & ATLAS_REG_PH_CALIB_STATUS_HIGH))
dev_warn(dev, "device missing high point calibration\n");
return 0;
}
static int atlas_check_ec_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
int ret;
unsigned int val;
ret = regmap_bulk_read(data->regmap, ATLAS_REG_EC_PROBE, &val, 2);
if (ret)
return ret;
dev_info(dev, "probe set to K = %d.%.2d", be16_to_cpu(val) / 100,
be16_to_cpu(val) % 100);
ret = regmap_read(data->regmap, ATLAS_REG_EC_CALIB_STATUS, &val);
if (ret)
return ret;
if (!(val & ATLAS_REG_EC_CALIB_STATUS_MASK)) {
dev_warn(dev, "device has not been calibrated\n");
return 0;
}
if (!(val & ATLAS_REG_EC_CALIB_STATUS_DRY))
dev_warn(dev, "device missing dry point calibration\n");
if (val & ATLAS_REG_EC_CALIB_STATUS_SINGLE) {
dev_warn(dev, "device using single point calibration\n");
} else {
if (!(val & ATLAS_REG_EC_CALIB_STATUS_LOW))
dev_warn(dev, "device missing low point calibration\n");
if (!(val & ATLAS_REG_EC_CALIB_STATUS_HIGH))
dev_warn(dev, "device missing high point calibration\n");
}
return 0;
}
struct atlas_device {
const struct iio_chan_spec *channels;
int num_channels;
int data_reg;
int (*calibration)(struct atlas_data *data);
int delay;
};
static struct atlas_device atlas_devices[] = {
[ATLAS_PH_SM] = {
.channels = atlas_ph_channels,
.num_channels = 3,
.data_reg = ATLAS_REG_PH_DATA,
.calibration = &atlas_check_ph_calibration,
.delay = ATLAS_PH_INT_TIME_IN_US,
},
[ATLAS_EC_SM] = {
.channels = atlas_ec_channels,
.num_channels = 5,
.data_reg = ATLAS_REG_EC_DATA,
.calibration = &atlas_check_ec_calibration,
.delay = ATLAS_EC_INT_TIME_IN_US,
},
};
static int atlas_set_powermode(struct atlas_data *data, int on)
{
return regmap_write(data->regmap, ATLAS_REG_PWR_CONTROL, on);
@ -178,12 +337,13 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
struct atlas_data *data = iio_priv(indio_dev);
int ret;
ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
(u8 *) &data->buffer, sizeof(data->buffer[0]));
ret = regmap_bulk_read(data->regmap, data->chip->data_reg,
(u8 *) &data->buffer,
sizeof(__be32) * (data->chip->num_channels - 2));
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);
@ -200,7 +360,7 @@ static irqreturn_t atlas_interrupt_handler(int irq, void *private)
return IRQ_HANDLED;
}
static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val)
{
struct device *dev = &data->client->dev;
int suspended = pm_runtime_suspended(dev);
@ -213,11 +373,9 @@ static int atlas_read_ph_measurement(struct atlas_data *data, __be32 *val)
}
if (suspended)
usleep_range(ATLAS_PH_INT_TIME_IN_US,
ATLAS_PH_INT_TIME_IN_US + 100000);
usleep_range(data->chip->delay, data->chip->delay + 100000);
ret = regmap_bulk_read(data->regmap, ATLAS_REG_PH_DATA,
(u8 *) val, sizeof(*val));
ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val));
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@ -242,12 +400,15 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
(u8 *) &reg, sizeof(reg));
break;
case IIO_PH:
case IIO_CONCENTRATION:
case IIO_ELECTRICALCONDUCTIVITY:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = atlas_read_ph_measurement(data, &reg);
ret = atlas_read_measurement(data,
chan->address, &reg);
mutex_unlock(&indio_dev->mlock);
break;
@ -271,6 +432,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
*val = 1; /* 0.001 */
*val2 = 1000;
break;
case IIO_ELECTRICALCONDUCTIVITY:
*val = 1; /* 0.00001 */
*val = 100000;
break;
case IIO_CONCENTRATION:
*val = 0; /* 0.000000001 */
*val2 = 1000;
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
@ -303,37 +472,26 @@ static const struct iio_info atlas_info = {
.write_raw = atlas_write_raw,
};
static int atlas_check_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
int ret;
unsigned int val;
ret = regmap_read(data->regmap, ATLAS_REG_CALIB_STATUS, &val);
if (ret)
return ret;
if (!(val & ATLAS_REG_CALIB_STATUS_MASK)) {
dev_warn(dev, "device has not been calibrated\n");
return 0;
}
if (!(val & ATLAS_REG_CALIB_STATUS_LOW))
dev_warn(dev, "device missing low point calibration\n");
if (!(val & ATLAS_REG_CALIB_STATUS_MID))
dev_warn(dev, "device missing mid point calibration\n");
if (!(val & ATLAS_REG_CALIB_STATUS_HIGH))
dev_warn(dev, "device missing high point calibration\n");
return 0;
static const struct i2c_device_id atlas_id[] = {
{ "atlas-ph-sm", ATLAS_PH_SM},
{ "atlas-ec-sm", ATLAS_EC_SM},
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
static const struct of_device_id atlas_dt_ids[] = {
{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
static int atlas_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct atlas_data *data;
struct atlas_device *chip;
const struct of_device_id *of_id;
struct iio_trigger *trig;
struct iio_dev *indio_dev;
int ret;
@ -342,10 +500,16 @@ static int atlas_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
of_id = of_match_device(atlas_dt_ids, &client->dev);
if (!of_id)
chip = &atlas_devices[id->driver_data];
else
chip = &atlas_devices[(unsigned long)of_id->data];
indio_dev->info = &atlas_info;
indio_dev->name = ATLAS_DRV_NAME;
indio_dev->channels = atlas_channels;
indio_dev->num_channels = ARRAY_SIZE(atlas_channels);
indio_dev->channels = chip->channels;
indio_dev->num_channels = chip->num_channels;
indio_dev->modes = INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE;
indio_dev->dev.parent = &client->dev;
@ -358,6 +522,7 @@ static int atlas_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->client = client;
data->trig = trig;
data->chip = chip;
trig->dev.parent = indio_dev->dev.parent;
trig->ops = &atlas_interrupt_trigger_ops;
iio_trigger_set_drvdata(trig, indio_dev);
@ -379,7 +544,7 @@ static int atlas_probe(struct i2c_client *client,
return -EINVAL;
}
ret = atlas_check_calibration(data);
ret = chip->calibration(data);
if (ret)
return ret;
@ -480,18 +645,6 @@ static const struct dev_pm_ops atlas_pm_ops = {
atlas_runtime_resume, NULL)
};
static const struct i2c_device_id atlas_id[] = {
{ "atlas-ph-sm", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
static const struct of_device_id atlas_dt_ids[] = {
{ .compatible = "atlas,ph-sm" },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
static struct i2c_driver atlas_driver = {
.driver = {
.name = ATLAS_DRV_NAME,

View File

@ -22,34 +22,32 @@
#include <linux/iio/common/st_sensors.h>
int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
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;
}
EXPORT_SYMBOL(st_sensors_get_buffer_element);
irqreturn_t st_sensors_trigger_handler(int irq, void *p)
{
@ -59,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)

View File

@ -228,7 +228,7 @@ int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
void st_sensors_power_enable(struct iio_dev *indio_dev)
int st_sensors_power_enable(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
int err;
@ -237,18 +237,37 @@ void st_sensors_power_enable(struct iio_dev *indio_dev)
pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
if (!IS_ERR(pdata->vdd)) {
err = regulator_enable(pdata->vdd);
if (err != 0)
if (err != 0) {
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd supply\n");
return err;
}
} else {
err = PTR_ERR(pdata->vdd);
if (err != -ENODEV)
return err;
}
pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
if (!IS_ERR(pdata->vdd_io)) {
err = regulator_enable(pdata->vdd_io);
if (err != 0)
if (err != 0) {
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd_IO supply\n");
goto st_sensors_disable_vdd;
}
} else {
err = PTR_ERR(pdata->vdd_io);
if (err != -ENODEV)
goto st_sensors_disable_vdd;
}
return 0;
st_sensors_disable_vdd:
if (!IS_ERR_OR_NULL(pdata->vdd))
regulator_disable(pdata->vdd);
return err;
}
EXPORT_SYMBOL(st_sensors_power_enable);
@ -256,10 +275,10 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
if (!IS_ERR(pdata->vdd))
if (!IS_ERR_OR_NULL(pdata->vdd))
regulator_disable(pdata->vdd);
if (!IS_ERR(pdata->vdd_io))
if (!IS_ERR_OR_NULL(pdata->vdd_io))
regulator_disable(pdata->vdd_io);
}
EXPORT_SYMBOL(st_sensors_power_disable);
@ -471,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)
@ -531,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);
@ -551,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 =

View File

@ -48,8 +48,8 @@ static int st_sensors_i2c_read_multiple_byte(
if (multiread_bit)
reg_addr |= ST_SENSORS_I2C_MULTIREAD;
return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
reg_addr, len, data);
return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev),
reg_addr, len, data);
}
static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,

View File

@ -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,

View File

@ -248,11 +248,12 @@ config MCP4922
config STX104
tristate "Apex Embedded Systems STX104 DAC driver"
depends on X86 && ISA_BUS_API
select GPIOLIB
help
Say yes here to build support for the 2-channel DAC on the Apex
Embedded Systems STX104 integrated analog PC/104 card. The base port
addresses for the devices may be configured via the "base" module
parameter array.
Say yes here to build support for the 2-channel DAC and GPIO on the
Apex Embedded Systems STX104 integrated analog PC/104 card. The base
port addresses for the devices may be configured via the base array
module parameter.
config VF610_DAC
tristate "Vybrid vf610 DAC driver"

View File

@ -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;

View File

@ -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;
}

View File

@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/ad5755.h>
@ -109,6 +110,51 @@ enum ad5755_type {
ID_AD5737,
};
#ifdef CONFIG_OF
static const int ad5755_dcdc_freq_table[][2] = {
{ 250000, AD5755_DC_DC_FREQ_250kHZ },
{ 410000, AD5755_DC_DC_FREQ_410kHZ },
{ 650000, AD5755_DC_DC_FREQ_650kHZ }
};
static const int ad5755_dcdc_maxv_table[][2] = {
{ 23000000, AD5755_DC_DC_MAXV_23V },
{ 24500000, AD5755_DC_DC_MAXV_24V5 },
{ 27000000, AD5755_DC_DC_MAXV_27V },
{ 29500000, AD5755_DC_DC_MAXV_29V5 },
};
static const int ad5755_slew_rate_table[][2] = {
{ 64000, AD5755_SLEW_RATE_64k },
{ 32000, AD5755_SLEW_RATE_32k },
{ 16000, AD5755_SLEW_RATE_16k },
{ 8000, AD5755_SLEW_RATE_8k },
{ 4000, AD5755_SLEW_RATE_4k },
{ 2000, AD5755_SLEW_RATE_2k },
{ 1000, AD5755_SLEW_RATE_1k },
{ 500, AD5755_SLEW_RATE_500 },
{ 250, AD5755_SLEW_RATE_250 },
{ 125, AD5755_SLEW_RATE_125 },
{ 64, AD5755_SLEW_RATE_64 },
{ 32, AD5755_SLEW_RATE_32 },
{ 16, AD5755_SLEW_RATE_16 },
{ 8, AD5755_SLEW_RATE_8 },
{ 4, AD5755_SLEW_RATE_4 },
{ 0, AD5755_SLEW_RATE_0_5 },
};
static const int ad5755_slew_step_table[][2] = {
{ 256, AD5755_SLEW_STEP_SIZE_256 },
{ 128, AD5755_SLEW_STEP_SIZE_128 },
{ 64, AD5755_SLEW_STEP_SIZE_64 },
{ 32, AD5755_SLEW_STEP_SIZE_32 },
{ 16, AD5755_SLEW_STEP_SIZE_16 },
{ 4, AD5755_SLEW_STEP_SIZE_4 },
{ 2, AD5755_SLEW_STEP_SIZE_2 },
{ 1, AD5755_SLEW_STEP_SIZE_1 },
};
#endif
static int ad5755_write_unlocked(struct iio_dev *indio_dev,
unsigned int reg, unsigned int val)
{
@ -556,6 +602,129 @@ static const struct ad5755_platform_data ad5755_default_pdata = {
},
};
#ifdef CONFIG_OF
static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
struct device_node *pp;
struct ad5755_platform_data *pdata;
unsigned int tmp;
unsigned int tmparray[3];
int devnr, i;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
pdata->ext_dc_dc_compenstation_resistor =
of_property_read_bool(np, "adi,ext-dc-dc-compenstation-resistor");
if (!of_property_read_u32(np, "adi,dc-dc-phase", &tmp))
pdata->dc_dc_phase = tmp;
else
pdata->dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE;
pdata->dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ;
if (!of_property_read_u32(np, "adi,dc-dc-freq-hz", &tmp)) {
for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_freq_table); i++) {
if (tmp == ad5755_dcdc_freq_table[i][0]) {
pdata->dc_dc_freq = ad5755_dcdc_freq_table[i][1];
break;
}
}
if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) {
dev_err(dev,
"adi,dc-dc-freq out of range selecting 410kHz");
}
}
pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V;
if (!of_property_read_u32(np, "adi,dc-dc-max-microvolt", &tmp)) {
for (i = 0; i < ARRAY_SIZE(ad5755_dcdc_maxv_table); i++) {
if (tmp == ad5755_dcdc_maxv_table[i][0]) {
pdata->dc_dc_maxv = ad5755_dcdc_maxv_table[i][1];
break;
}
}
if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) {
dev_err(dev,
"adi,dc-dc-maxv out of range selecting 23V");
}
}
devnr = 0;
for_each_child_of_node(np, pp) {
if (devnr > AD5755_NUM_CHANNELS) {
dev_err(dev,
"There is to many channels defined in DT\n");
goto error_out;
}
if (!of_property_read_u32(pp, "adi,mode", &tmp))
pdata->dac[devnr].mode = tmp;
else
pdata->dac[devnr].mode = AD5755_MODE_CURRENT_4mA_20mA;
pdata->dac[devnr].ext_current_sense_resistor =
of_property_read_bool(pp, "adi,ext-current-sense-resistor");
pdata->dac[devnr].enable_voltage_overrange =
of_property_read_bool(pp, "adi,enable-voltage-overrange");
if (!of_property_read_u32_array(pp, "adi,slew", tmparray, 3)) {
pdata->dac[devnr].slew.enable = tmparray[0];
pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k;
for (i = 0; i < ARRAY_SIZE(ad5755_slew_rate_table); i++) {
if (tmparray[1] == ad5755_slew_rate_table[i][0]) {
pdata->dac[devnr].slew.rate =
ad5755_slew_rate_table[i][1];
break;
}
}
if (i == ARRAY_SIZE(ad5755_slew_rate_table)) {
dev_err(dev,
"channel %d slew rate out of range selecting 64kHz",
devnr);
}
pdata->dac[devnr].slew.step_size = AD5755_SLEW_STEP_SIZE_1;
for (i = 0; i < ARRAY_SIZE(ad5755_slew_step_table); i++) {
if (tmparray[2] == ad5755_slew_step_table[i][0]) {
pdata->dac[devnr].slew.step_size =
ad5755_slew_step_table[i][1];
break;
}
}
if (i == ARRAY_SIZE(ad5755_slew_step_table)) {
dev_err(dev,
"channel %d slew step size out of range selecting 1 LSB",
devnr);
}
} else {
pdata->dac[devnr].slew.enable = false;
pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k;
pdata->dac[devnr].slew.step_size =
AD5755_SLEW_STEP_SIZE_1;
}
devnr++;
}
return pdata;
error_out:
devm_kfree(dev, pdata);
return NULL;
}
#else
static
struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
{
return NULL;
}
#endif
static int ad5755_probe(struct spi_device *spi)
{
enum ad5755_type type = spi_get_device_id(spi)->driver_data;
@ -583,8 +752,15 @@ static int ad5755_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = AD5755_NUM_CHANNELS;
if (!pdata)
if (spi->dev.of_node)
pdata = ad5755_parse_dt(&spi->dev);
else
pdata = spi->dev.platform_data;
if (!pdata) {
dev_warn(&spi->dev, "no platform data? using default\n");
pdata = &ad5755_default_pdata;
}
ret = ad5755_init_channels(indio_dev, pdata);
if (ret)
@ -607,6 +783,16 @@ static const struct spi_device_id ad5755_id[] = {
};
MODULE_DEVICE_TABLE(spi, ad5755_id);
static const struct of_device_id ad5755_of_match[] = {
{ .compatible = "adi,ad5755" },
{ .compatible = "adi,ad5755-1" },
{ .compatible = "adi,ad5757" },
{ .compatible = "adi,ad5735" },
{ .compatible = "adi,ad5737" },
{ }
};
MODULE_DEVICE_TABLE(of, ad5755_of_match);
static struct spi_driver ad5755_driver = {
.driver = {
.name = "ad5755",

View File

@ -14,6 +14,7 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/io.h>
@ -21,6 +22,7 @@
#include <linux/isa.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#define STX104_NUM_CHAN 2
@ -49,6 +51,20 @@ struct stx104_iio {
unsigned base;
};
/**
* struct stx104_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @base: base port address of the GPIO device
* @out_state: output bits state
*/
struct stx104_gpio {
struct gpio_chip chip;
spinlock_t lock;
unsigned int base;
unsigned int out_state;
};
static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
@ -88,15 +104,81 @@ static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
STX104_CHAN(1)
};
static int stx104_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
if (offset < 4)
return 1;
return 0;
}
static int stx104_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
if (offset >= 4)
return -EINVAL;
return 0;
}
static int stx104_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
if (offset < 4)
return -EINVAL;
chip->set(chip, offset, value);
return 0;
}
static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
if (offset >= 4)
return -EINVAL;
return !!(inb(stx104gpio->base) & BIT(offset));
}
static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
const unsigned int mask = BIT(offset) >> 4;
unsigned long flags;
if (offset < 4)
return;
spin_lock_irqsave(&stx104gpio->lock, flags);
if (value)
stx104gpio->out_state |= mask;
else
stx104gpio->out_state &= ~mask;
outb(stx104gpio->out_state, stx104gpio->base);
spin_unlock_irqrestore(&stx104gpio->lock, flags);
}
static int stx104_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct stx104_iio *priv;
struct stx104_gpio *stx104gpio;
int err;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
if (!stx104gpio)
return -ENOMEM;
if (!devm_request_region(dev, base[id], STX104_EXTENT,
dev_name(dev))) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@ -117,14 +199,53 @@ static int stx104_probe(struct device *dev, unsigned int id)
outw(0, base[id] + 4);
outw(0, base[id] + 6);
return devm_iio_device_register(dev, indio_dev);
err = devm_iio_device_register(dev, indio_dev);
if (err) {
dev_err(dev, "IIO device registering failed (%d)\n", err);
return err;
}
stx104gpio->chip.label = dev_name(dev);
stx104gpio->chip.parent = dev;
stx104gpio->chip.owner = THIS_MODULE;
stx104gpio->chip.base = -1;
stx104gpio->chip.ngpio = 8;
stx104gpio->chip.get_direction = stx104_gpio_get_direction;
stx104gpio->chip.direction_input = stx104_gpio_direction_input;
stx104gpio->chip.direction_output = stx104_gpio_direction_output;
stx104gpio->chip.get = stx104_gpio_get;
stx104gpio->chip.set = stx104_gpio_set;
stx104gpio->base = base[id] + 3;
stx104gpio->out_state = 0x0;
spin_lock_init(&stx104gpio->lock);
dev_set_drvdata(dev, stx104gpio);
err = gpiochip_add_data(&stx104gpio->chip, stx104gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
}
return 0;
}
static int stx104_remove(struct device *dev, unsigned int id)
{
struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev);
gpiochip_remove(&stx104gpio->chip);
return 0;
}
static struct isa_driver stx104_driver = {
.probe = stx104_probe,
.driver = {
.name = "stx104"
}
},
.remove = stx104_remove
};
module_isa_driver(stx104_driver, num_stx104);

View File

@ -10,6 +10,7 @@ config IIO_DUMMY_EVGEN
config IIO_SIMPLE_DUMMY
tristate "An example driver with no hardware requirements"
depends on IIO_SW_DEVICE
help
Driver intended mainly as documentation for how to write
a driver. May also be useful for testing userspace code

View File

@ -17,26 +17,18 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sw_device.h>
#include "iio_simple_dummy.h"
/*
* A few elements needed to fake a bus for this driver
* Note instances parameter controls how many of these
* dummy devices are registered.
*/
static unsigned instances = 1;
module_param(instances, uint, 0);
/* Pointer array used to fake bus elements */
static struct iio_dev **iio_dummy_devs;
/* Fake a name for the part number, usually obtained from the id table */
static const char *iio_dummy_part_number = "iio_dummy_part_no";
static struct config_item_type iio_dummy_type = {
.ct_owner = THIS_MODULE,
};
/**
* struct iio_dummy_accel_calibscale - realworld to register mapping
@ -572,12 +564,18 @@ static int iio_dummy_init_device(struct iio_dev *indio_dev)
* const struct i2c_device_id *id)
* SPI: iio_dummy_probe(struct spi_device *spi)
*/
static int iio_dummy_probe(int index)
static struct iio_sw_device *iio_dummy_probe(const char *name)
{
int ret;
struct iio_dev *indio_dev;
struct iio_dummy_state *st;
struct iio_sw_device *swd;
swd = kzalloc(sizeof(*swd), GFP_KERNEL);
if (!swd) {
ret = -ENOMEM;
goto error_kzalloc;
}
/*
* Allocate an IIO device.
*
@ -608,7 +606,7 @@ static int iio_dummy_probe(int index)
* i2c_set_clientdata(client, indio_dev);
* spi_set_drvdata(spi, indio_dev);
*/
iio_dummy_devs[index] = indio_dev;
swd->device = indio_dev;
/*
* Set the device name.
@ -619,7 +617,7 @@ static int iio_dummy_probe(int index)
* indio_dev->name = id->name;
* indio_dev->name = spi_get_device_id(spi)->name;
*/
indio_dev->name = iio_dummy_part_number;
indio_dev->name = kstrdup(name, GFP_KERNEL);
/* Provide description of available channels */
indio_dev->channels = iio_dummy_channels;
@ -646,7 +644,9 @@ static int iio_dummy_probe(int index)
if (ret < 0)
goto error_unconfigure_buffer;
return 0;
iio_swd_group_init_type_name(swd, name, &iio_dummy_type);
return swd;
error_unconfigure_buffer:
iio_simple_dummy_unconfigure_buffer(indio_dev);
error_unregister_events:
@ -654,16 +654,18 @@ error_unregister_events:
error_free_device:
iio_device_free(indio_dev);
error_ret:
return ret;
kfree(swd);
error_kzalloc:
return ERR_PTR(ret);
}
/**
* iio_dummy_remove() - device instance removal function
* @index: device index.
* @swd: pointer to software IIO device abstraction
*
* Parameters follow those of iio_dummy_probe for buses.
*/
static void iio_dummy_remove(int index)
static int iio_dummy_remove(struct iio_sw_device *swd)
{
/*
* Get a pointer to the device instance iio_dev structure
@ -671,7 +673,7 @@ static void iio_dummy_remove(int index)
* struct iio_dev *indio_dev = i2c_get_clientdata(client);
* struct iio_dev *indio_dev = spi_get_drvdata(spi);
*/
struct iio_dev *indio_dev = iio_dummy_devs[index];
struct iio_dev *indio_dev = swd->device;
/* Unregister the device */
iio_device_unregister(indio_dev);
@ -684,11 +686,13 @@ static void iio_dummy_remove(int index)
iio_simple_dummy_events_unregister(indio_dev);
/* Free all structures */
kfree(indio_dev->name);
iio_device_free(indio_dev);
}
return 0;
}
/**
* iio_dummy_init() - device driver registration
* module_iio_sw_device_driver() - device driver registration
*
* Varies depending on bus type of the device. As there is no device
* here, call probe directly. For information on device registration
@ -697,50 +701,18 @@ static void iio_dummy_remove(int index)
* spi:
* Documentation/spi/spi-summary
*/
static __init int iio_dummy_init(void)
{
int i, ret;
static const struct iio_sw_device_ops iio_dummy_device_ops = {
.probe = iio_dummy_probe,
.remove = iio_dummy_remove,
};
if (instances > 10) {
instances = 1;
return -EINVAL;
}
static struct iio_sw_device_type iio_dummy_device = {
.name = "dummy",
.owner = THIS_MODULE,
.ops = &iio_dummy_device_ops,
};
/* Fake a bus */
iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs),
GFP_KERNEL);
/* Here we have no actual device so call probe */
for (i = 0; i < instances; i++) {
ret = iio_dummy_probe(i);
if (ret < 0)
goto error_remove_devs;
}
return 0;
error_remove_devs:
while (i--)
iio_dummy_remove(i);
kfree(iio_dummy_devs);
return ret;
}
module_init(iio_dummy_init);
/**
* iio_dummy_exit() - device driver removal
*
* Varies depending on bus type of the device.
* As there is no device here, call remove directly.
*/
static __exit void iio_dummy_exit(void)
{
int i;
for (i = 0; i < instances; i++)
iio_dummy_remove(i);
kfree(iio_dummy_devs);
}
module_exit(iio_dummy_exit);
module_iio_sw_device_driver(iio_dummy_device);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("IIO dummy driver");

View File

@ -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);

View File

@ -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;
}

View File

@ -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) {

View File

@ -426,13 +426,15 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
indio_dev->info = &gyro_info;
mutex_init(&gdata->tb.buf_lock);
st_sensors_power_enable(indio_dev);
err = st_sensors_power_enable(indio_dev);
if (err)
return err;
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_gyro_sensors_settings),
st_gyro_sensors_settings);
if (err < 0)
return err;
goto st_gyro_power_off;
gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
gdata->multiread_bit = gdata->sensor_settings->multi_read_bit;
@ -446,11 +448,11 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
err = st_sensors_init_sensor(indio_dev,
(struct st_sensors_platform_data *)&gyro_pdata);
if (err < 0)
return err;
goto st_gyro_power_off;
err = st_gyro_allocate_ring(indio_dev);
if (err < 0)
return err;
goto st_gyro_power_off;
if (irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
@ -473,6 +475,8 @@ st_gyro_device_register_error:
st_sensors_deallocate_trigger(indio_dev);
st_gyro_probe_trigger_error:
st_gyro_deallocate_ring(indio_dev);
st_gyro_power_off:
st_sensors_power_disable(indio_dev);
return err;
}

View File

@ -1,7 +1,7 @@
/*
* AFE4403 Heart Rate Monitors and Low-Cost Pulse Oximeters
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
* This program is free software; you can redistribute it and/or modify
@ -39,127 +39,90 @@
#define AFE4403_TIAGAIN 0x20
#define AFE4403_TIA_AMB_GAIN 0x21
/* AFE4403 GAIN register fields */
#define AFE4403_TIAGAIN_RES_MASK GENMASK(2, 0)
#define AFE4403_TIAGAIN_RES_SHIFT 0
#define AFE4403_TIAGAIN_CAP_MASK GENMASK(7, 3)
#define AFE4403_TIAGAIN_CAP_SHIFT 3
enum afe4403_fields {
/* Gains */
F_RF_LED1, F_CF_LED1,
F_RF_LED, F_CF_LED,
/* AFE4403 LEDCNTRL register fields */
#define AFE440X_LEDCNTRL_LED1_MASK GENMASK(15, 8)
#define AFE440X_LEDCNTRL_LED1_SHIFT 8
#define AFE440X_LEDCNTRL_LED2_MASK GENMASK(7, 0)
#define AFE440X_LEDCNTRL_LED2_SHIFT 0
#define AFE440X_LEDCNTRL_LED_RANGE_MASK GENMASK(17, 16)
#define AFE440X_LEDCNTRL_LED_RANGE_SHIFT 16
/* LED Current */
F_ILED1, F_ILED2,
/* AFE4403 CONTROL2 register fields */
#define AFE440X_CONTROL2_PWR_DWN_TX BIT(2)
#define AFE440X_CONTROL2_EN_SLOW_DIAG BIT(8)
#define AFE440X_CONTROL2_DIAG_OUT_TRI BIT(10)
#define AFE440X_CONTROL2_TX_BRDG_MOD BIT(11)
#define AFE440X_CONTROL2_TX_REF_MASK GENMASK(18, 17)
#define AFE440X_CONTROL2_TX_REF_SHIFT 17
/* sentinel */
F_MAX_FIELDS
};
/* AFE4404 NULL fields */
#define NULL_MASK 0
#define NULL_SHIFT 0
/* AFE4403 LEDCNTRL values */
#define AFE440X_LEDCNTRL_RANGE_TX_HALF 0x1
#define AFE440X_LEDCNTRL_RANGE_TX_FULL 0x2
#define AFE440X_LEDCNTRL_RANGE_TX_OFF 0x3
/* AFE4403 CONTROL2 values */
#define AFE440X_CONTROL2_TX_REF_025 0x0
#define AFE440X_CONTROL2_TX_REF_050 0x1
#define AFE440X_CONTROL2_TX_REF_100 0x2
#define AFE440X_CONTROL2_TX_REF_075 0x3
/* AFE4403 CONTROL3 values */
#define AFE440X_CONTROL3_CLK_DIV_2 0x0
#define AFE440X_CONTROL3_CLK_DIV_4 0x2
#define AFE440X_CONTROL3_CLK_DIV_6 0x3
#define AFE440X_CONTROL3_CLK_DIV_8 0x4
#define AFE440X_CONTROL3_CLK_DIV_12 0x5
#define AFE440X_CONTROL3_CLK_DIV_1 0x7
/* AFE4403 TIAGAIN_CAP values */
#define AFE4403_TIAGAIN_CAP_5_P 0x0
#define AFE4403_TIAGAIN_CAP_10_P 0x1
#define AFE4403_TIAGAIN_CAP_20_P 0x2
#define AFE4403_TIAGAIN_CAP_30_P 0x3
#define AFE4403_TIAGAIN_CAP_55_P 0x8
#define AFE4403_TIAGAIN_CAP_155_P 0x10
/* AFE4403 TIAGAIN_RES values */
#define AFE4403_TIAGAIN_RES_500_K 0x0
#define AFE4403_TIAGAIN_RES_250_K 0x1
#define AFE4403_TIAGAIN_RES_100_K 0x2
#define AFE4403_TIAGAIN_RES_50_K 0x3
#define AFE4403_TIAGAIN_RES_25_K 0x4
#define AFE4403_TIAGAIN_RES_10_K 0x5
#define AFE4403_TIAGAIN_RES_1_M 0x6
#define AFE4403_TIAGAIN_RES_NONE 0x7
static const struct reg_field afe4403_reg_fields[] = {
/* Gains */
[F_RF_LED1] = REG_FIELD(AFE4403_TIAGAIN, 0, 2),
[F_CF_LED1] = REG_FIELD(AFE4403_TIAGAIN, 3, 7),
[F_RF_LED] = REG_FIELD(AFE4403_TIA_AMB_GAIN, 0, 2),
[F_CF_LED] = REG_FIELD(AFE4403_TIA_AMB_GAIN, 3, 7),
/* LED Current */
[F_ILED1] = REG_FIELD(AFE440X_LEDCNTRL, 0, 7),
[F_ILED2] = REG_FIELD(AFE440X_LEDCNTRL, 8, 15),
};
/**
* struct afe4403_data
* @dev - Device structure
* @spi - SPI device handle
* @regmap - Register map of the device
* @regulator - Pointer to the regulator for the IC
* @trig - IIO trigger for this device
* @irq - ADC_RDY line interrupt number
* struct afe4403_data - AFE4403 device instance data
* @dev: Device structure
* @spi: SPI device handle
* @regmap: Register map of the device
* @fields: Register fields of the device
* @regulator: Pointer to the regulator for the IC
* @trig: IIO trigger for this device
* @irq: ADC_RDY line interrupt number
*/
struct afe4403_data {
struct device *dev;
struct spi_device *spi;
struct regmap *regmap;
struct regmap_field *fields[F_MAX_FIELDS];
struct regulator *regulator;
struct iio_trigger *trig;
int irq;
};
enum afe4403_chan_id {
LED2 = 1,
ALED2,
LED1,
ALED1,
LED2,
ALED2,
LED1_ALED1,
LED2_ALED2,
ILED1,
ILED2,
LED1_ALED1,
};
static const struct afe440x_reg_info afe4403_reg_info[] = {
[LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, 0, NULL),
[ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, 0, NULL),
[LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, 0, NULL),
[ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL),
[LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL),
[LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL),
[ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED1),
[ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE440X_LEDCNTRL_LED2),
static const unsigned int afe4403_channel_values[] = {
[LED2] = AFE440X_LED2VAL,
[ALED2] = AFE440X_ALED2VAL,
[LED1] = AFE440X_LED1VAL,
[ALED1] = AFE440X_ALED1VAL,
[LED2_ALED2] = AFE440X_LED2_ALED2VAL,
[LED1_ALED1] = AFE440X_LED1_ALED1VAL,
};
static const unsigned int afe4403_channel_leds[] = {
[LED2] = F_ILED2,
[LED1] = F_ILED1,
};
static const struct iio_chan_spec afe4403_channels[] = {
/* ADC values */
AFE440X_INTENSITY_CHAN(LED1, "led1", 0),
AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", 0),
AFE440X_INTENSITY_CHAN(LED2, "led2", 0),
AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", 0),
AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0),
AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0),
AFE440X_INTENSITY_CHAN(LED2, 0),
AFE440X_INTENSITY_CHAN(ALED2, 0),
AFE440X_INTENSITY_CHAN(LED1, 0),
AFE440X_INTENSITY_CHAN(ALED1, 0),
AFE440X_INTENSITY_CHAN(LED2_ALED2, 0),
AFE440X_INTENSITY_CHAN(LED1_ALED1, 0),
/* LED current */
AFE440X_CURRENT_CHAN(ILED1, "led1"),
AFE440X_CURRENT_CHAN(ILED2, "led2"),
AFE440X_CURRENT_CHAN(LED2),
AFE440X_CURRENT_CHAN(LED1),
};
static const struct afe440x_val_table afe4403_res_table[] = {
{ 500000 }, { 250000 }, { 100000 }, { 50000 },
{ 25000 }, { 10000 }, { 1000000 }, { 0 },
};
AFE440X_TABLE_ATTR(tia_resistance_available, afe4403_res_table);
AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4403_res_table);
static const struct afe440x_val_table afe4403_cap_table[] = {
{ 0, 5000 }, { 0, 10000 }, { 0, 20000 }, { 0, 25000 },
@ -171,7 +134,7 @@ static const struct afe440x_val_table afe4403_cap_table[] = {
{ 0, 205000 }, { 0, 210000 }, { 0, 220000 }, { 0, 225000 },
{ 0, 230000 }, { 0, 235000 }, { 0, 245000 }, { 0, 250000 },
};
AFE440X_TABLE_ATTR(tia_capacitance_available, afe4403_cap_table);
AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4403_cap_table);
static ssize_t afe440x_show_register(struct device *dev,
struct device_attribute *attr,
@ -180,38 +143,21 @@ static ssize_t afe440x_show_register(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct afe4403_data *afe = iio_priv(indio_dev);
struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr);
unsigned int reg_val, type;
unsigned int reg_val;
int vals[2];
int ret, val_len;
int ret;
ret = regmap_read(afe->regmap, afe440x_attr->reg, &reg_val);
ret = regmap_field_read(afe->fields[afe440x_attr->field], &reg_val);
if (ret)
return ret;
reg_val &= afe440x_attr->mask;
reg_val >>= afe440x_attr->shift;
switch (afe440x_attr->type) {
case SIMPLE:
type = IIO_VAL_INT;
val_len = 1;
vals[0] = reg_val;
break;
case RESISTANCE:
case CAPACITANCE:
type = IIO_VAL_INT_PLUS_MICRO;
val_len = 2;
if (reg_val < afe440x_attr->table_size) {
vals[0] = afe440x_attr->val_table[reg_val].integer;
vals[1] = afe440x_attr->val_table[reg_val].fract;
break;
}
if (reg_val >= afe440x_attr->table_size)
return -EINVAL;
default:
return -EINVAL;
}
return iio_format_value(buf, type, val_len, vals);
vals[0] = afe440x_attr->val_table[reg_val].integer;
vals[1] = afe440x_attr->val_table[reg_val].fract;
return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals);
}
static ssize_t afe440x_store_register(struct device *dev,
@ -227,48 +173,43 @@ static ssize_t afe440x_store_register(struct device *dev,
if (ret)
return ret;
switch (afe440x_attr->type) {
case SIMPLE:
val = integer;
break;
case RESISTANCE:
case CAPACITANCE:
for (val = 0; val < afe440x_attr->table_size; val++)
if (afe440x_attr->val_table[val].integer == integer &&
afe440x_attr->val_table[val].fract == fract)
break;
if (val == afe440x_attr->table_size)
return -EINVAL;
break;
default:
for (val = 0; val < afe440x_attr->table_size; val++)
if (afe440x_attr->val_table[val].integer == integer &&
afe440x_attr->val_table[val].fract == fract)
break;
if (val == afe440x_attr->table_size)
return -EINVAL;
}
ret = regmap_update_bits(afe->regmap, afe440x_attr->reg,
afe440x_attr->mask,
(val << afe440x_attr->shift));
ret = regmap_field_write(afe->fields[afe440x_attr->field], val);
if (ret)
return ret;
return count;
}
static AFE440X_ATTR(tia_separate_en, AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0);
static AFE440X_ATTR(in_intensity1_resistance, F_RF_LED, afe4403_res_table);
static AFE440X_ATTR(in_intensity1_capacitance, F_CF_LED, afe4403_cap_table);
static AFE440X_ATTR(tia_resistance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_RES, RESISTANCE, afe4403_res_table, ARRAY_SIZE(afe4403_res_table));
static AFE440X_ATTR(tia_capacitance1, AFE4403_TIAGAIN, AFE4403_TIAGAIN_CAP, CAPACITANCE, afe4403_cap_table, ARRAY_SIZE(afe4403_cap_table));
static AFE440X_ATTR(in_intensity2_resistance, F_RF_LED, afe4403_res_table);
static AFE440X_ATTR(in_intensity2_capacitance, F_CF_LED, afe4403_cap_table);
static AFE440X_ATTR(tia_resistance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, RESISTANCE, afe4403_res_table, ARRAY_SIZE(afe4403_res_table));
static AFE440X_ATTR(tia_capacitance2, AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES, CAPACITANCE, afe4403_cap_table, ARRAY_SIZE(afe4403_cap_table));
static AFE440X_ATTR(in_intensity3_resistance, F_RF_LED1, afe4403_res_table);
static AFE440X_ATTR(in_intensity3_capacitance, F_CF_LED1, afe4403_cap_table);
static AFE440X_ATTR(in_intensity4_resistance, F_RF_LED1, afe4403_res_table);
static AFE440X_ATTR(in_intensity4_capacitance, F_CF_LED1, afe4403_cap_table);
static struct attribute *afe440x_attributes[] = {
&afe440x_attr_tia_separate_en.dev_attr.attr,
&afe440x_attr_tia_resistance1.dev_attr.attr,
&afe440x_attr_tia_capacitance1.dev_attr.attr,
&afe440x_attr_tia_resistance2.dev_attr.attr,
&afe440x_attr_tia_capacitance2.dev_attr.attr,
&dev_attr_tia_resistance_available.attr,
&dev_attr_tia_capacitance_available.attr,
&dev_attr_in_intensity_resistance_available.attr,
&dev_attr_in_intensity_capacitance_available.attr,
&afe440x_attr_in_intensity1_resistance.dev_attr.attr,
&afe440x_attr_in_intensity1_capacitance.dev_attr.attr,
&afe440x_attr_in_intensity2_resistance.dev_attr.attr,
&afe440x_attr_in_intensity2_capacitance.dev_attr.attr,
&afe440x_attr_in_intensity3_resistance.dev_attr.attr,
&afe440x_attr_in_intensity3_capacitance.dev_attr.attr,
&afe440x_attr_in_intensity4_resistance.dev_attr.attr,
&afe440x_attr_in_intensity4_capacitance.dev_attr.attr,
NULL
};
@ -309,35 +250,26 @@ static int afe4403_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct afe4403_data *afe = iio_priv(indio_dev);
const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address];
unsigned int reg = afe4403_channel_values[chan->address];
unsigned int field = afe4403_channel_leds[chan->address];
int ret;
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = afe4403_read(afe, reg_info.reg, val);
ret = afe4403_read(afe, reg, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
ret = regmap_read(afe->regmap, reg_info.offreg,
val);
if (ret)
return ret;
*val &= reg_info.mask;
*val >>= reg_info.shift;
return IIO_VAL_INT;
}
break;
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = regmap_read(afe->regmap, reg_info.reg, val);
ret = regmap_field_read(afe->fields[field], val);
if (ret)
return ret;
*val &= reg_info.mask;
*val >>= reg_info.shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
@ -357,25 +289,13 @@ static int afe4403_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct afe4403_data *afe = iio_priv(indio_dev);
const struct afe440x_reg_info reg_info = afe4403_reg_info[chan->address];
unsigned int field = afe4403_channel_leds[chan->address];
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_OFFSET:
return regmap_update_bits(afe->regmap,
reg_info.offreg,
reg_info.mask,
(val << reg_info.shift));
}
break;
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
return regmap_update_bits(afe->regmap,
reg_info.reg,
reg_info.mask,
(val << reg_info.shift));
return regmap_field_write(afe->fields[field], val);
}
break;
default:
@ -410,7 +330,7 @@ static irqreturn_t afe4403_trigger_handler(int irq, void *private)
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = spi_write_then_read(afe->spi,
&afe4403_reg_info[bit].reg, 1,
&afe4403_channel_values[bit], 1,
rx, 3);
if (ret)
goto err;
@ -472,12 +392,8 @@ static const struct iio_trigger_ops afe4403_trigger_ops = {
static const struct reg_sequence afe4403_reg_sequences[] = {
AFE4403_TIMING_PAIRS,
{ AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN | 0x000007},
{ AFE4403_TIA_AMB_GAIN, AFE4403_TIAGAIN_RES_1_M },
{ AFE440X_LEDCNTRL, (0x14 << AFE440X_LEDCNTRL_LED1_SHIFT) |
(0x14 << AFE440X_LEDCNTRL_LED2_SHIFT) },
{ AFE440X_CONTROL2, AFE440X_CONTROL2_TX_REF_050 <<
AFE440X_CONTROL2_TX_REF_SHIFT },
{ AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN },
{ AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN },
};
static const struct regmap_range afe4403_yes_ranges[] = {
@ -498,13 +414,11 @@ static const struct regmap_config afe4403_regmap_config = {
.volatile_table = &afe4403_volatile_table,
};
#ifdef CONFIG_OF
static const struct of_device_id afe4403_of_match[] = {
{ .compatible = "ti,afe4403", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, afe4403_of_match);
#endif
static int __maybe_unused afe4403_suspend(struct device *dev)
{
@ -553,7 +467,7 @@ static int afe4403_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct afe4403_data *afe;
int ret;
int i, ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*afe));
if (!indio_dev)
@ -572,6 +486,15 @@ static int afe4403_probe(struct spi_device *spi)
return PTR_ERR(afe->regmap);
}
for (i = 0; i < F_MAX_FIELDS; i++) {
afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap,
afe4403_reg_fields[i]);
if (IS_ERR(afe->fields[i])) {
dev_err(afe->dev, "Unable to allocate regmap fields\n");
return PTR_ERR(afe->fields[i]);
}
}
afe->regulator = devm_regulator_get(afe->dev, "tx_sup");
if (IS_ERR(afe->regulator)) {
dev_err(afe->dev, "Unable to get regulator\n");
@ -694,7 +617,7 @@ MODULE_DEVICE_TABLE(spi, afe4403_ids);
static struct spi_driver afe4403_spi_driver = {
.driver = {
.name = AFE4403_DRIVER_NAME,
.of_match_table = of_match_ptr(afe4403_of_match),
.of_match_table = afe4403_of_match,
.pm = &afe4403_pm_ops,
},
.probe = afe4403_probe,
@ -704,5 +627,5 @@ static struct spi_driver afe4403_spi_driver = {
module_spi_driver(afe4403_spi_driver);
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("TI AFE4403 Heart Rate and Pulse Oximeter");
MODULE_DESCRIPTION("TI AFE4403 Heart Rate Monitor and Pulse Oximeter AFE");
MODULE_LICENSE("GPL v2");

View File

@ -1,7 +1,7 @@
/*
* AFE4404 Heart Rate Monitors and Low-Cost Pulse Oximeters
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/
* Andrew F. Davis <afd@ti.com>
*
* This program is free software; you can redistribute it and/or modify
@ -48,118 +48,102 @@
#define AFE4404_AVG_LED2_ALED2VAL 0x3f
#define AFE4404_AVG_LED1_ALED1VAL 0x40
/* AFE4404 GAIN register fields */
#define AFE4404_TIA_GAIN_RES_MASK GENMASK(2, 0)
#define AFE4404_TIA_GAIN_RES_SHIFT 0
#define AFE4404_TIA_GAIN_CAP_MASK GENMASK(5, 3)
#define AFE4404_TIA_GAIN_CAP_SHIFT 3
/* AFE4404 LEDCNTRL register fields */
#define AFE4404_LEDCNTRL_ILED1_MASK GENMASK(5, 0)
#define AFE4404_LEDCNTRL_ILED1_SHIFT 0
#define AFE4404_LEDCNTRL_ILED2_MASK GENMASK(11, 6)
#define AFE4404_LEDCNTRL_ILED2_SHIFT 6
#define AFE4404_LEDCNTRL_ILED3_MASK GENMASK(17, 12)
#define AFE4404_LEDCNTRL_ILED3_SHIFT 12
/* AFE4404 CONTROL2 register fields */
#define AFE440X_CONTROL2_ILED_2X_MASK BIT(17)
#define AFE440X_CONTROL2_ILED_2X_SHIFT 17
#define AFE440X_CONTROL2_OSC_ENABLE BIT(9)
/* AFE4404 CONTROL3 register fields */
#define AFE440X_CONTROL3_OSC_ENABLE BIT(9)
enum afe4404_fields {
/* Gains */
F_TIA_GAIN_SEP, F_TIA_CF_SEP,
F_TIA_GAIN, TIA_CF,
/* AFE4404 OFFDAC register current fields */
#define AFE4404_OFFDAC_CURR_LED1_MASK GENMASK(9, 5)
#define AFE4404_OFFDAC_CURR_LED1_SHIFT 5
#define AFE4404_OFFDAC_CURR_LED2_MASK GENMASK(19, 15)
#define AFE4404_OFFDAC_CURR_LED2_SHIFT 15
#define AFE4404_OFFDAC_CURR_LED3_MASK GENMASK(4, 0)
#define AFE4404_OFFDAC_CURR_LED3_SHIFT 0
#define AFE4404_OFFDAC_CURR_ALED1_MASK GENMASK(14, 10)
#define AFE4404_OFFDAC_CURR_ALED1_SHIFT 10
#define AFE4404_OFFDAC_CURR_ALED2_MASK GENMASK(4, 0)
#define AFE4404_OFFDAC_CURR_ALED2_SHIFT 0
/* LED Current */
F_ILED1, F_ILED2, F_ILED3,
/* AFE4404 NULL fields */
#define NULL_MASK 0
#define NULL_SHIFT 0
/* Offset DAC */
F_OFFDAC_AMB2, F_OFFDAC_LED1, F_OFFDAC_AMB1, F_OFFDAC_LED2,
/* AFE4404 TIA_GAIN_CAP values */
#define AFE4404_TIA_GAIN_CAP_5_P 0x0
#define AFE4404_TIA_GAIN_CAP_2_5_P 0x1
#define AFE4404_TIA_GAIN_CAP_10_P 0x2
#define AFE4404_TIA_GAIN_CAP_7_5_P 0x3
#define AFE4404_TIA_GAIN_CAP_20_P 0x4
#define AFE4404_TIA_GAIN_CAP_17_5_P 0x5
#define AFE4404_TIA_GAIN_CAP_25_P 0x6
#define AFE4404_TIA_GAIN_CAP_22_5_P 0x7
/* sentinel */
F_MAX_FIELDS
};
/* AFE4404 TIA_GAIN_RES values */
#define AFE4404_TIA_GAIN_RES_500_K 0x0
#define AFE4404_TIA_GAIN_RES_250_K 0x1
#define AFE4404_TIA_GAIN_RES_100_K 0x2
#define AFE4404_TIA_GAIN_RES_50_K 0x3
#define AFE4404_TIA_GAIN_RES_25_K 0x4
#define AFE4404_TIA_GAIN_RES_10_K 0x5
#define AFE4404_TIA_GAIN_RES_1_M 0x6
#define AFE4404_TIA_GAIN_RES_2_M 0x7
static const struct reg_field afe4404_reg_fields[] = {
/* Gains */
[F_TIA_GAIN_SEP] = REG_FIELD(AFE4404_TIA_GAIN_SEP, 0, 2),
[F_TIA_CF_SEP] = REG_FIELD(AFE4404_TIA_GAIN_SEP, 3, 5),
[F_TIA_GAIN] = REG_FIELD(AFE4404_TIA_GAIN, 0, 2),
[TIA_CF] = REG_FIELD(AFE4404_TIA_GAIN, 3, 5),
/* LED Current */
[F_ILED1] = REG_FIELD(AFE440X_LEDCNTRL, 0, 5),
[F_ILED2] = REG_FIELD(AFE440X_LEDCNTRL, 6, 11),
[F_ILED3] = REG_FIELD(AFE440X_LEDCNTRL, 12, 17),
/* Offset DAC */
[F_OFFDAC_AMB2] = REG_FIELD(AFE4404_OFFDAC, 0, 4),
[F_OFFDAC_LED1] = REG_FIELD(AFE4404_OFFDAC, 5, 9),
[F_OFFDAC_AMB1] = REG_FIELD(AFE4404_OFFDAC, 10, 14),
[F_OFFDAC_LED2] = REG_FIELD(AFE4404_OFFDAC, 15, 19),
};
/**
* struct afe4404_data
* @dev - Device structure
* @regmap - Register map of the device
* @regulator - Pointer to the regulator for the IC
* @trig - IIO trigger for this device
* @irq - ADC_RDY line interrupt number
* struct afe4404_data - AFE4404 device instance data
* @dev: Device structure
* @regmap: Register map of the device
* @fields: Register fields of the device
* @regulator: Pointer to the regulator for the IC
* @trig: IIO trigger for this device
* @irq: ADC_RDY line interrupt number
*/
struct afe4404_data {
struct device *dev;
struct regmap *regmap;
struct regmap_field *fields[F_MAX_FIELDS];
struct regulator *regulator;
struct iio_trigger *trig;
int irq;
};
enum afe4404_chan_id {
LED2 = 1,
ALED2,
LED1,
ALED1,
LED2,
ALED2,
LED3,
LED1_ALED1,
LED2_ALED2,
ILED1,
ILED2,
ILED3,
LED1_ALED1,
};
static const struct afe440x_reg_info afe4404_reg_info[] = {
[LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1),
[ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1),
[LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2),
[ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2),
[LED3] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL),
[LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL),
[LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL),
[ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1),
[ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED2),
[ILED3] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED3),
static const unsigned int afe4404_channel_values[] = {
[LED2] = AFE440X_LED2VAL,
[ALED2] = AFE440X_ALED2VAL,
[LED1] = AFE440X_LED1VAL,
[ALED1] = AFE440X_ALED1VAL,
[LED2_ALED2] = AFE440X_LED2_ALED2VAL,
[LED1_ALED1] = AFE440X_LED1_ALED1VAL,
};
static const unsigned int afe4404_channel_leds[] = {
[LED2] = F_ILED2,
[ALED2] = F_ILED3,
[LED1] = F_ILED1,
};
static const unsigned int afe4404_channel_offdacs[] = {
[LED2] = F_OFFDAC_LED2,
[ALED2] = F_OFFDAC_AMB2,
[LED1] = F_OFFDAC_LED1,
[ALED1] = F_OFFDAC_AMB1,
};
static const struct iio_chan_spec afe4404_channels[] = {
/* ADC values */
AFE440X_INTENSITY_CHAN(LED1, "led1", BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(LED2, "led2", BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(LED3, "led3", BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0),
AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0),
AFE440X_INTENSITY_CHAN(LED2, BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(ALED2, BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(LED1, BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(ALED1, BIT(IIO_CHAN_INFO_OFFSET)),
AFE440X_INTENSITY_CHAN(LED2_ALED2, 0),
AFE440X_INTENSITY_CHAN(LED1_ALED1, 0),
/* LED current */
AFE440X_CURRENT_CHAN(ILED1, "led1"),
AFE440X_CURRENT_CHAN(ILED2, "led2"),
AFE440X_CURRENT_CHAN(ILED3, "led3"),
AFE440X_CURRENT_CHAN(LED2),
AFE440X_CURRENT_CHAN(ALED2),
AFE440X_CURRENT_CHAN(LED1),
};
static const struct afe440x_val_table afe4404_res_table[] = {
@ -172,7 +156,7 @@ static const struct afe440x_val_table afe4404_res_table[] = {
{ .integer = 1000000, .fract = 0 },
{ .integer = 2000000, .fract = 0 },
};
AFE440X_TABLE_ATTR(tia_resistance_available, afe4404_res_table);
AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4404_res_table);
static const struct afe440x_val_table afe4404_cap_table[] = {
{ .integer = 0, .fract = 5000 },
@ -184,7 +168,7 @@ static const struct afe440x_val_table afe4404_cap_table[] = {
{ .integer = 0, .fract = 25000 },
{ .integer = 0, .fract = 22500 },
};
AFE440X_TABLE_ATTR(tia_capacitance_available, afe4404_cap_table);
AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4404_cap_table);
static ssize_t afe440x_show_register(struct device *dev,
struct device_attribute *attr,
@ -193,38 +177,21 @@ static ssize_t afe440x_show_register(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct afe4404_data *afe = iio_priv(indio_dev);
struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr);
unsigned int reg_val, type;
unsigned int reg_val;
int vals[2];
int ret, val_len;
int ret;
ret = regmap_read(afe->regmap, afe440x_attr->reg, &reg_val);
ret = regmap_field_read(afe->fields[afe440x_attr->field], &reg_val);
if (ret)
return ret;
reg_val &= afe440x_attr->mask;
reg_val >>= afe440x_attr->shift;
switch (afe440x_attr->type) {
case SIMPLE:
type = IIO_VAL_INT;
val_len = 1;
vals[0] = reg_val;
break;
case RESISTANCE:
case CAPACITANCE:
type = IIO_VAL_INT_PLUS_MICRO;
val_len = 2;
if (reg_val < afe440x_attr->table_size) {
vals[0] = afe440x_attr->val_table[reg_val].integer;
vals[1] = afe440x_attr->val_table[reg_val].fract;
break;
}
if (reg_val >= afe440x_attr->table_size)
return -EINVAL;
default:
return -EINVAL;
}
return iio_format_value(buf, type, val_len, vals);
vals[0] = afe440x_attr->val_table[reg_val].integer;
vals[1] = afe440x_attr->val_table[reg_val].fract;
return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals);
}
static ssize_t afe440x_store_register(struct device *dev,
@ -240,48 +207,43 @@ static ssize_t afe440x_store_register(struct device *dev,
if (ret)
return ret;
switch (afe440x_attr->type) {
case SIMPLE:
val = integer;
break;
case RESISTANCE:
case CAPACITANCE:
for (val = 0; val < afe440x_attr->table_size; val++)
if (afe440x_attr->val_table[val].integer == integer &&
afe440x_attr->val_table[val].fract == fract)
break;
if (val == afe440x_attr->table_size)
return -EINVAL;
break;
default:
for (val = 0; val < afe440x_attr->table_size; val++)
if (afe440x_attr->val_table[val].integer == integer &&
afe440x_attr->val_table[val].fract == fract)
break;
if (val == afe440x_attr->table_size)
return -EINVAL;
}
ret = regmap_update_bits(afe->regmap, afe440x_attr->reg,
afe440x_attr->mask,
(val << afe440x_attr->shift));
ret = regmap_field_write(afe->fields[afe440x_attr->field], val);
if (ret)
return ret;
return count;
}
static AFE440X_ATTR(tia_separate_en, AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0);
static AFE440X_ATTR(in_intensity1_resistance, F_TIA_GAIN_SEP, afe4404_res_table);
static AFE440X_ATTR(in_intensity1_capacitance, F_TIA_CF_SEP, afe4404_cap_table);
static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table));
static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table));
static AFE440X_ATTR(in_intensity2_resistance, F_TIA_GAIN_SEP, afe4404_res_table);
static AFE440X_ATTR(in_intensity2_capacitance, F_TIA_CF_SEP, afe4404_cap_table);
static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table));
static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table));
static AFE440X_ATTR(in_intensity3_resistance, F_TIA_GAIN, afe4404_res_table);
static AFE440X_ATTR(in_intensity3_capacitance, TIA_CF, afe4404_cap_table);
static AFE440X_ATTR(in_intensity4_resistance, F_TIA_GAIN, afe4404_res_table);
static AFE440X_ATTR(in_intensity4_capacitance, TIA_CF, afe4404_cap_table);
static struct attribute *afe440x_attributes[] = {
&afe440x_attr_tia_separate_en.dev_attr.attr,
&afe440x_attr_tia_resistance1.dev_attr.attr,
&afe440x_attr_tia_capacitance1.dev_attr.attr,
&afe440x_attr_tia_resistance2.dev_attr.attr,
&afe440x_attr_tia_capacitance2.dev_attr.attr,
&dev_attr_tia_resistance_available.attr,
&dev_attr_tia_capacitance_available.attr,
&dev_attr_in_intensity_resistance_available.attr,
&dev_attr_in_intensity_capacitance_available.attr,
&afe440x_attr_in_intensity1_resistance.dev_attr.attr,
&afe440x_attr_in_intensity1_capacitance.dev_attr.attr,
&afe440x_attr_in_intensity2_resistance.dev_attr.attr,
&afe440x_attr_in_intensity2_capacitance.dev_attr.attr,
&afe440x_attr_in_intensity3_resistance.dev_attr.attr,
&afe440x_attr_in_intensity3_capacitance.dev_attr.attr,
&afe440x_attr_in_intensity4_resistance.dev_attr.attr,
&afe440x_attr_in_intensity4_capacitance.dev_attr.attr,
NULL
};
@ -294,35 +256,32 @@ static int afe4404_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct afe4404_data *afe = iio_priv(indio_dev);
const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address];
unsigned int value_reg = afe4404_channel_values[chan->address];
unsigned int led_field = afe4404_channel_leds[chan->address];
unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
int ret;
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = regmap_read(afe->regmap, reg_info.reg, val);
ret = regmap_read(afe->regmap, value_reg, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
ret = regmap_read(afe->regmap, reg_info.offreg,
val);
ret = regmap_field_read(afe->fields[offdac_field], val);
if (ret)
return ret;
*val &= reg_info.mask;
*val >>= reg_info.shift;
return IIO_VAL_INT;
}
break;
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = regmap_read(afe->regmap, reg_info.reg, val);
ret = regmap_field_read(afe->fields[led_field], val);
if (ret)
return ret;
*val &= reg_info.mask;
*val >>= reg_info.shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
@ -342,25 +301,20 @@ static int afe4404_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct afe4404_data *afe = iio_priv(indio_dev);
const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address];
unsigned int led_field = afe4404_channel_leds[chan->address];
unsigned int offdac_field = afe4404_channel_offdacs[chan->address];
switch (chan->type) {
case IIO_INTENSITY:
switch (mask) {
case IIO_CHAN_INFO_OFFSET:
return regmap_update_bits(afe->regmap,
reg_info.offreg,
reg_info.mask,
(val << reg_info.shift));
return regmap_field_write(afe->fields[offdac_field], val);
}
break;
case IIO_CURRENT:
switch (mask) {
case IIO_CHAN_INFO_RAW:
return regmap_update_bits(afe->regmap,
reg_info.reg,
reg_info.mask,
(val << reg_info.shift));
return regmap_field_write(afe->fields[led_field], val);
}
break;
default:
@ -387,7 +341,7 @@ static irqreturn_t afe4404_trigger_handler(int irq, void *private)
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = regmap_read(afe->regmap, afe4404_reg_info[bit].reg,
ret = regmap_read(afe->regmap, afe4404_channel_values[bit],
&buffer[i++]);
if (ret)
goto err;
@ -443,11 +397,8 @@ static const struct iio_trigger_ops afe4404_trigger_ops = {
static const struct reg_sequence afe4404_reg_sequences[] = {
AFE4404_TIMING_PAIRS,
{ AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN },
{ AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES_50_K },
{ AFE440X_LEDCNTRL, (0xf << AFE4404_LEDCNTRL_ILED1_SHIFT) |
(0x3 << AFE4404_LEDCNTRL_ILED2_SHIFT) |
(0x3 << AFE4404_LEDCNTRL_ILED3_SHIFT) },
{ AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE },
{ AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN },
{ AFE440X_CONTROL2, AFE440X_CONTROL2_OSC_ENABLE },
};
static const struct regmap_range afe4404_yes_ranges[] = {
@ -469,13 +420,11 @@ static const struct regmap_config afe4404_regmap_config = {
.volatile_table = &afe4404_volatile_table,
};
#ifdef CONFIG_OF
static const struct of_device_id afe4404_of_match[] = {
{ .compatible = "ti,afe4404", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, afe4404_of_match);
#endif
static int __maybe_unused afe4404_suspend(struct device *dev)
{
@ -525,7 +474,7 @@ static int afe4404_probe(struct i2c_client *client,
{
struct iio_dev *indio_dev;
struct afe4404_data *afe;
int ret;
int i, ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*afe));
if (!indio_dev)
@ -543,6 +492,15 @@ static int afe4404_probe(struct i2c_client *client,
return PTR_ERR(afe->regmap);
}
for (i = 0; i < F_MAX_FIELDS; i++) {
afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap,
afe4404_reg_fields[i]);
if (IS_ERR(afe->fields[i])) {
dev_err(afe->dev, "Unable to allocate regmap fields\n");
return PTR_ERR(afe->fields[i]);
}
}
afe->regulator = devm_regulator_get(afe->dev, "tx_sup");
if (IS_ERR(afe->regulator)) {
dev_err(afe->dev, "Unable to get regulator\n");
@ -665,7 +623,7 @@ MODULE_DEVICE_TABLE(i2c, afe4404_ids);
static struct i2c_driver afe4404_i2c_driver = {
.driver = {
.name = AFE4404_DRIVER_NAME,
.of_match_table = of_match_ptr(afe4404_of_match),
.of_match_table = afe4404_of_match,
.pm = &afe4404_pm_ops,
},
.probe = afe4404_probe,
@ -675,5 +633,5 @@ static struct i2c_driver afe4404_i2c_driver = {
module_i2c_driver(afe4404_i2c_driver);
MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
MODULE_DESCRIPTION("TI AFE4404 Heart Rate and Pulse Oximeter");
MODULE_DESCRIPTION("TI AFE4404 Heart Rate Monitor and Pulse Oximeter AFE");
MODULE_LICENSE("GPL v2");

View File

@ -71,8 +71,7 @@
#define AFE440X_CONTROL1_TIMEREN BIT(8)
/* TIAGAIN register fields */
#define AFE440X_TIAGAIN_ENSEPGAIN_MASK BIT(15)
#define AFE440X_TIAGAIN_ENSEPGAIN_SHIFT 15
#define AFE440X_TIAGAIN_ENSEPGAIN BIT(15)
/* CONTROL2 register fields */
#define AFE440X_CONTROL2_PDN_AFE BIT(0)
@ -89,22 +88,7 @@
#define AFE440X_CONTROL0_WRITE 0x0
#define AFE440X_CONTROL0_READ 0x1
struct afe440x_reg_info {
unsigned int reg;
unsigned int offreg;
unsigned int shift;
unsigned int mask;
};
#define AFE440X_REG_INFO(_reg, _offreg, _sm) \
{ \
.reg = _reg, \
.offreg = _offreg, \
.shift = _sm ## _SHIFT, \
.mask = _sm ## _MASK, \
}
#define AFE440X_INTENSITY_CHAN(_index, _name, _mask) \
#define AFE440X_INTENSITY_CHAN(_index, _mask) \
{ \
.type = IIO_INTENSITY, \
.channel = _index, \
@ -116,29 +100,23 @@ struct afe440x_reg_info {
.storagebits = 32, \
.endianness = IIO_CPU, \
}, \
.extend_name = _name, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
_mask, \
.indexed = true, \
}
#define AFE440X_CURRENT_CHAN(_index, _name) \
#define AFE440X_CURRENT_CHAN(_index) \
{ \
.type = IIO_CURRENT, \
.channel = _index, \
.address = _index, \
.scan_index = _index, \
.extend_name = _name, \
.scan_index = -1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.indexed = true, \
.output = true, \
}
enum afe440x_reg_type {
SIMPLE,
RESISTANCE,
CAPACITANCE,
};
struct afe440x_val_table {
int integer;
int fract;
@ -164,10 +142,7 @@ static DEVICE_ATTR_RO(_name)
struct afe440x_attr {
struct device_attribute dev_attr;
unsigned int reg;
unsigned int shift;
unsigned int mask;
enum afe440x_reg_type type;
unsigned int field;
const struct afe440x_val_table *val_table;
unsigned int table_size;
};
@ -175,17 +150,14 @@ struct afe440x_attr {
#define to_afe440x_attr(_dev_attr) \
container_of(_dev_attr, struct afe440x_attr, dev_attr)
#define AFE440X_ATTR(_name, _reg, _field, _type, _table, _size) \
#define AFE440X_ATTR(_name, _field, _table) \
struct afe440x_attr afe440x_attr_##_name = { \
.dev_attr = __ATTR(_name, (S_IRUGO | S_IWUSR), \
afe440x_show_register, \
afe440x_store_register), \
.reg = _reg, \
.shift = _field ## _SHIFT, \
.mask = _field ## _MASK, \
.type = _type, \
.field = _field, \
.val_table = _table, \
.table_size = _size, \
.table_size = ARRAY_SIZE(_table), \
}
#endif /* _AFE440X_H */

View File

@ -276,6 +276,7 @@ static const struct i2c_device_id am2315_i2c_id[] = {
{"am2315", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, am2315_i2c_id);
static const struct acpi_device_id am2315_acpi_id[] = {
{"AOS2315", 0},

View File

@ -236,6 +236,7 @@ static const struct i2c_device_id htu21_id[] = {
{"ms8607-humidity", MS8607},
{}
};
MODULE_DEVICE_TABLE(i2c, htu21_id);
static struct i2c_driver htu21_driver = {
.probe = htu21_probe,

View File

@ -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

View File

@ -20,6 +20,7 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include "bmi160.h"
@ -410,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;
@ -466,10 +468,36 @@ static int bmi160_write_raw(struct iio_dev *indio_dev,
return 0;
}
static
IIO_CONST_ATTR(in_accel_sampling_frequency_available,
"0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600");
static
IIO_CONST_ATTR(in_anglvel_sampling_frequency_available,
"25 50 100 200 400 800 1600 3200");
static
IIO_CONST_ATTR(in_accel_scale_available,
"0.000598 0.001197 0.002394 0.004788");
static
IIO_CONST_ATTR(in_anglvel_scale_available,
"0.001065 0.000532 0.000266 0.000133 0.000066");
static struct attribute *bmi160_attrs[] = {
&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_in_anglvel_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
&iio_const_attr_in_anglvel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group bmi160_attrs_group = {
.attrs = bmi160_attrs,
};
static const struct iio_info bmi160_info = {
.driver_module = THIS_MODULE,
.read_raw = bmi160_read_raw,
.write_raw = bmi160_write_raw,
.attrs = &bmi160_attrs_group,
};
static const char *bmi160_match_acpi_device(struct device *dev)

View File

@ -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.

View File

@ -113,6 +113,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
.reg = &reg_set_6050,
.config = &chip_config_6050,
},
{
.whoami = INV_ICM20608_WHOAMI_VALUE,
.name = "ICM20608",
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
};
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)

View File

@ -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},
{}
};

View File

@ -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 {

View File

@ -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, &timestamp, 1,
&st->time_stamp_lock);

View File

@ -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},
{}
};

View File

@ -80,6 +80,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_RESISTANCE] = "resistance",
[IIO_PH] = "ph",
[IIO_UVINDEX] = "uvindex",
[IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
};
static const char * const iio_modifier_names[] = {
@ -177,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;
@ -989,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) {
@ -1008,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]),
@ -1038,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;

View File

@ -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;
}

View File

@ -0,0 +1,182 @@
/*
* The Industrial I/O core, software IIO devices functions
*
* Copyright (c) 2016 Intel Corporation
*
* 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.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/iio/sw_device.h>
#include <linux/iio/configfs.h>
#include <linux/configfs.h>
static struct config_group *iio_devices_group;
static struct config_item_type iio_device_type_group_type;
static struct config_item_type iio_devices_group_type = {
.ct_owner = THIS_MODULE,
};
static LIST_HEAD(iio_device_types_list);
static DEFINE_MUTEX(iio_device_types_lock);
static
struct iio_sw_device_type *__iio_find_sw_device_type(const char *name,
unsigned len)
{
struct iio_sw_device_type *d = NULL, *iter;
list_for_each_entry(iter, &iio_device_types_list, list)
if (!strcmp(iter->name, name)) {
d = iter;
break;
}
return d;
}
int iio_register_sw_device_type(struct iio_sw_device_type *d)
{
struct iio_sw_device_type *iter;
int ret = 0;
mutex_lock(&iio_device_types_lock);
iter = __iio_find_sw_device_type(d->name, strlen(d->name));
if (iter)
ret = -EBUSY;
else
list_add_tail(&d->list, &iio_device_types_list);
mutex_unlock(&iio_device_types_lock);
if (ret)
return ret;
d->group = configfs_register_default_group(iio_devices_group, d->name,
&iio_device_type_group_type);
if (IS_ERR(d->group))
ret = PTR_ERR(d->group);
return ret;
}
EXPORT_SYMBOL(iio_register_sw_device_type);
void iio_unregister_sw_device_type(struct iio_sw_device_type *dt)
{
struct iio_sw_device_type *iter;
mutex_lock(&iio_device_types_lock);
iter = __iio_find_sw_device_type(dt->name, strlen(dt->name));
if (iter)
list_del(&dt->list);
mutex_unlock(&iio_device_types_lock);
configfs_unregister_default_group(dt->group);
}
EXPORT_SYMBOL(iio_unregister_sw_device_type);
static
struct iio_sw_device_type *iio_get_sw_device_type(const char *name)
{
struct iio_sw_device_type *dt;
mutex_lock(&iio_device_types_lock);
dt = __iio_find_sw_device_type(name, strlen(name));
if (dt && !try_module_get(dt->owner))
dt = NULL;
mutex_unlock(&iio_device_types_lock);
return dt;
}
struct iio_sw_device *iio_sw_device_create(const char *type, const char *name)
{
struct iio_sw_device *d;
struct iio_sw_device_type *dt;
dt = iio_get_sw_device_type(type);
if (!dt) {
pr_err("Invalid device type: %s\n", type);
return ERR_PTR(-EINVAL);
}
d = dt->ops->probe(name);
if (IS_ERR(d))
goto out_module_put;
d->device_type = dt;
return d;
out_module_put:
module_put(dt->owner);
return d;
}
EXPORT_SYMBOL(iio_sw_device_create);
void iio_sw_device_destroy(struct iio_sw_device *d)
{
struct iio_sw_device_type *dt = d->device_type;
dt->ops->remove(d);
module_put(dt->owner);
}
EXPORT_SYMBOL(iio_sw_device_destroy);
static struct config_group *device_make_group(struct config_group *group,
const char *name)
{
struct iio_sw_device *d;
d = iio_sw_device_create(group->cg_item.ci_name, name);
if (IS_ERR(d))
return ERR_CAST(d);
config_item_set_name(&d->group.cg_item, "%s", name);
return &d->group;
}
static void device_drop_group(struct config_group *group,
struct config_item *item)
{
struct iio_sw_device *d = to_iio_sw_device(item);
iio_sw_device_destroy(d);
config_item_put(item);
}
static struct configfs_group_operations device_ops = {
.make_group = &device_make_group,
.drop_item = &device_drop_group,
};
static struct config_item_type iio_device_type_group_type = {
.ct_group_ops = &device_ops,
.ct_owner = THIS_MODULE,
};
static int __init iio_sw_device_init(void)
{
iio_devices_group =
configfs_register_default_group(&iio_configfs_subsys.su_group,
"devices",
&iio_devices_group_type);
return PTR_ERR_OR_ZERO(iio_devices_group);
}
module_init(iio_sw_device_init);
static void __exit iio_sw_device_exit(void)
{
configfs_unregister_default_group(iio_devices_group);
}
module_exit(iio_sw_device_exit);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("Industrial I/O software devices support");
MODULE_LICENSE("GPL v2");

View File

@ -64,10 +64,16 @@ static struct attribute *iio_trig_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(iio_trig_dev);
static struct iio_trigger *__iio_trigger_find_by_name(const char *name);
int iio_trigger_register(struct iio_trigger *trig_info)
{
int ret;
/* trig_info->ops is required for the module member */
if (!trig_info->ops)
return -EINVAL;
trig_info->id = ida_simple_get(&iio_trigger_ida, 0, 0, GFP_KERNEL);
if (trig_info->id < 0)
return trig_info->id;
@ -82,11 +88,19 @@ int iio_trigger_register(struct iio_trigger *trig_info)
/* Add to list of available triggers held by the IIO core */
mutex_lock(&iio_trigger_list_lock);
if (__iio_trigger_find_by_name(trig_info->name)) {
pr_err("Duplicate trigger name '%s'\n", trig_info->name);
ret = -EEXIST;
goto error_device_del;
}
list_add_tail(&trig_info->list, &iio_trigger_list);
mutex_unlock(&iio_trigger_list_lock);
return 0;
error_device_del:
mutex_unlock(&iio_trigger_list_lock);
device_del(&trig_info->dev);
error_unregister_id:
ida_simple_remove(&iio_trigger_ida, trig_info->id);
return ret;
@ -105,6 +119,18 @@ void iio_trigger_unregister(struct iio_trigger *trig_info)
}
EXPORT_SYMBOL(iio_trigger_unregister);
/* Search for trigger by name, assuming iio_trigger_list_lock held */
static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
{
struct iio_trigger *iter;
list_for_each_entry(iter, &iio_trigger_list, list)
if (!strcmp(iter->name, name))
return iter;
return NULL;
}
static struct iio_trigger *iio_trigger_find_by_name(const char *name,
size_t len)
{
@ -164,8 +190,7 @@ EXPORT_SYMBOL(iio_trigger_poll_chained);
void iio_trigger_notify_done(struct iio_trigger *trig)
{
if (atomic_dec_and_test(&trig->use_count) && trig->ops &&
trig->ops->try_reenable)
if (atomic_dec_and_test(&trig->use_count) && trig->ops->try_reenable)
if (trig->ops->try_reenable(trig))
/* Missed an interrupt so launch new poll now */
iio_trigger_poll(trig);
@ -224,7 +249,7 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
goto out_put_irq;
/* Enable trigger in driver */
if (trig->ops && trig->ops->set_trigger_state && notinuse) {
if (trig->ops->set_trigger_state && notinuse) {
ret = trig->ops->set_trigger_state(trig, true);
if (ret < 0)
goto out_free_irq;
@ -249,7 +274,7 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
= (bitmap_weight(trig->pool,
CONFIG_IIO_CONSUMERS_PER_TRIGGER)
== 1);
if (trig->ops && trig->ops->set_trigger_state && no_other_users) {
if (trig->ops->set_trigger_state && no_other_users) {
ret = trig->ops->set_trigger_state(trig, false);
if (ret)
return ret;
@ -264,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);
@ -371,7 +396,7 @@ static ssize_t iio_trigger_write_current(struct device *dev,
return ret;
}
if (trig && trig->ops && trig->ops->validate_device) {
if (trig && trig->ops->validate_device) {
ret = trig->ops->validate_device(trig, indio_dev);
if (ret)
return ret;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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));
}
}
@ -1287,22 +1287,14 @@ static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev,
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
int err = -EINVAL;
mutex_lock(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev)) {
err = -EBUSY;
goto error_unlock;
}
if (mask == IIO_CHAN_INFO_RAW) {
err = iio_device_claim_direct_mode(indio_dev);
if (err)
return err;
err = gp2ap020a00f_read_channel(data, chan, val);
break;
iio_device_release_direct_mode(indio_dev);
}
error_unlock:
mutex_unlock(&data->lock);
return err < 0 ? err : IIO_VAL_INT;
}

Some files were not shown because too many files have changed in this diff Show More