Commit 932f9892 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-5.2a-2' of...

Merge tag 'iio-for-5.2a-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

First set of new device support, features and fixes for IIO in the 5.2 cycle

Staging graduations
* ad7780
  - Move this ADC driver out of staging.  Included adding some new features
    along the way (see below). Also added DT bindings.

New device support
* adis16480
  - Support the ADIS16495 and ADIS16497 IMU devices making
    heavy use of refactoring of various aspects of the driver in precursor
    patches.
* lsm6dsx
  - Support for the ASM330LHH 6-axis (accelerometer + gyro) sensor.
  - Support for the LSM6DS0X
* matbotix mb1232
  - New driver for this ultrasound ranging device family. Including bindings.
  - Supports mb1202, mb1212, mb1222, mb1232, mb1242, mb7040 and mb7137.
* max31856
  - New driver for this thermocouple temperature sensor.
* meson saradc
  - Support the Meson-G12A (ID addition only).
* stmpe-adc
  - New driver supporting generic ADC alongside touchscreen support which
    previously existed. Includes DT bindings.
* vcnl4000
  - Support for the vcln4040 proximity and light sensor, including adding
    DT bindings for this and parts previously supported.

Features
* core
  - Allow reading of mount matrices from ACPI in addition to DT.
  - Common binding for theromcouple types.
* ad5933
  - Add ABI docs as there are a few 'unsual' elements about this
    device - perhaps because it's our only impedance analyser.
* ad7780
  - Add gain and filter gpio support + readback of current gain and filter.
* adis16480
  - Allow selection fo the dataready pin to be used.
  - Device tree ID table and binding documentation.
  - Support external clock modes, including new bindings.
* bma180
  - Mount matrix support.
* bmc150
  - Mount matrix support.
* bmg160
  - Mount matrix support.
  - DT id table and bindings doc.
* bmp280
  - Put calibration data into the entropy pool.
* hmc5843
  - Mount matrix support.
* itg3200
  - Mount matrix support.
* kxcjk1013
  - Device tree id table, and binding docs.
* lpc32xx
  - Add scale when regulator specified including DT docs for regulator.
* pms7003
  - Add device IDs for all supported parts to driver and binding.
* stm32-dfsdm
  - Enable hw consumer support, scan mode control and a complex set of
    triggered buffer modes.
  - Power management.
* stm32-lptimer-counter
  - power management.
  - Document the pinctrl sleep state binding.
* ti-ads7950
  - GPIO pin support.

Cleanups, minor fixes
* core
  - Use bitmap_zalloc to make it explicit that is what we are doing.
  - Tidy up all the Kconfig files (which had slowly gotten messy)
  - Fix a forwards definition missing issue in iio/driver.h
* ad sigma delta core
  - Improve handling of SPI bus locking vs CS assertion.  This has been
    wrong a long time so not rushing this in.
* ad5064
  - Mlock to local lock.
* ad5933 (staging cleanup)
  - Multiline comment fixes.
  - Include ordering.
  - SPDX.
  - Tidy up Kconfig help which was a bit missleading.
  - Change some non standard attributes to ABI defined ones.
* ad7124
  - White space fix.
* ad7192
  - White space.
  - Use DT clock binding.
  - Improve error reporting.
  - Platform data to DT conversion.
  - Use read_avail callback, mostly to avoid the endless series of
    patches from new contributors trying to falsely put spaces around
    the negative sign.
* ad7280a
  - Add brackets to macros to avoid potential precedence isseus.
  - Add temp vars for event codes to reduce indent and improved readability.
  - Clean out som CamelCase notation.
  - White space.
* ad7606
  - Fix broken file naming in MAINTAINERS.
* ad7780
  - Missing switch defaults to supress warnings and harden the code slightly.
  - Set pattern masks more directly.
  - Add ID values and masks for all supported chips.
  - SPDX + add Renato as a copyright holder as he has done a lot of work on
    this driver.
  - Add brackets to macros to avoid potential precedence issues.
* ad7923
  - White space fixes.
  - Use BIT macro to improve readability.
  - Add brackets to macros to avoid potential precedence issues.
  - Tidy up a null comparisom.
* ad9523
  - Fix a typo in naming of variables.
* adis16400
  - Combine trigger file into main code as no advantage in separate files.
    Rename core file to just adis16400.
  - Squash the header into the c file now there is only one file.
  - Generalize burst mode to support new variants.
* ak8975
  - Local variable to improve readability around mount matrix support.
* as3935
  - Avoid potential race by ensuring remove does exact opposite of
    probe rather than a slightly different order.
* cross_ec
  - Drop some unnecessary includes.
  - Fix some warning and the slightly 'unusual' code.
  - Add some docs for non obvious function.
  - SPDX
* hmc5843
  - Potential unhandled error case.
* iio trigger core
  - Print an error if there is no available irq due to max consumers per
    trigger being set to low.
* iio loop trigger
  - Drop an unlikely on IS_ERR as IS_ERR already has the annotation.
* ingenic-adc
  - Drop a redundant dev_err call as devm_ioremap_resource reports the same
    internally.
* lmp91000
  - Drop some unncessary parentheses and white space tidy up.
  - Invert and if statement to improve readability.
  - Fix a wrong error message.
* lpc32xx
  - Header sorting + drop some unused ones.
* mma8542
  - Mark a switch fallthrough.
* mpu6050
  - Add a local variable to improve code readability around mount matrix
    support.
* mxs-lradc-adc
  - Handle devm_iio_trigger_alloc failure.
* sps30
  - Fix up a kernel version in the ABI docs.
* srf04
  - DT binding doc converted to yaml.
* ssp_sensors
  - Supress a clang build warning due to lack of visibility of conditional
    within a iio_push_to_buffers_with_timestamp.  (reasonable false warning!)
* st_accel
  - Drop pointless less than 0 comparisom of unsigned int.
* stm32-dfsdm
  - Improve accuracy of spi_master_frequency calculation.
  - Improve calculation fo sampling frequency.
  - Rework various internals to simplify adding triggered buffer support.
  - Claim direct mode to avoid racing around read_raw and being in buffered
    mode.
* stmpe
  - Fix a clang false positive warning.
* ti-ads7950
  - Use local lock rather than using the core mlock when not locking around
    the device mode.
* vcnl4000
  - Use word writes instead of byte writes.  It seems byte writes are fine
    for some parts (undocument) but not others that the driver will shortly
    support.

Other
* mailmap
  - Add email address change for Sean Nyekjaer.  Update in relevant drivers

* tag 'iio-for-5.2a-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (129 commits)
  iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion
  iio: adc: stm32-dfsdm: add PM support
  iio: adc: stm32-dfsdm: improve sampling frequency accuracy
  staging: iio: adc: ad7280a: Tab alignment
  MAINTAINERS: Fix the link to ad7606 dt-bindings
  iio:temperature: Add MAX31856 thermocouple support
  iio:temperature:max31856:Add device tree bind info
  dt-bindings: iio/temperature: Add thermocouple types (and doc)
  devantech-srf04.yaml: transform DT binding to YAML
  iio: frequency: ad9523: Fix typo in ad9523_platform_data
  iio: Make possible to include driver.h first
  dt-bindings: iio: add Bosch BMG160 gyroscope sensor
  iio: gyro: bmg160: add device tree compatibility table
  staging: iio: adc: ad7192: Use read_avail for available attributes
  dt-bindings: iio: light: add vcnl4040 devicetree bindings
  iio: light: vcnl4000 add support for the VCNL4040 proximity and light sensor
  dt-bindings: iio: light: add vcnl4000 devicetree bindings
  iio: light: vcnl4000 add devicetree hooks
  iio: light: vcnl4000 use word writes instead of byte writes
  iio: adc: stm32-dfsdm: claim direct mode for raw read and settings
  ...
parents 44b8ef17 df1d80ae
...@@ -187,6 +187,7 @@ Santosh Shilimkar <ssantosh@kernel.org> ...@@ -187,6 +187,7 @@ Santosh Shilimkar <ssantosh@kernel.org>
Santosh Shilimkar <santosh.shilimkar@oracle.org> Santosh Shilimkar <santosh.shilimkar@oracle.org>
Sascha Hauer <s.hauer@pengutronix.de> Sascha Hauer <s.hauer@pengutronix.de>
S.Çağlar Onur <caglar@pardus.org.tr> S.Çağlar Onur <caglar@pardus.org.tr>
Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
Sebastian Reichel <sre@kernel.org> <sre@debian.org> Sebastian Reichel <sre@kernel.org> <sre@debian.org>
Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com> Shiraz Hashim <shiraz.linux.kernel@gmail.com> <shiraz.hashim@st.com>
......
What: /sys/bus/iio/devices/iio:deviceX/outY_freq_start What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_start
Date: March 2019
KernelVersion: 3.1.0 KernelVersion: 3.1.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Frequency sweep start frequency in Hz. Frequency sweep start frequency in Hz.
What: /sys/bus/iio/devices/iio:deviceX/outY_freq_increment What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_increment
Date: March 2019
KernelVersion: 3.1.0 KernelVersion: 3.1.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Frequency increment in Hz (step size) between consecutive Frequency increment in Hz (step size) between consecutive
frequency points along the sweep. frequency points along the sweep.
What: /sys/bus/iio/devices/iio:deviceX/outY_freq_points What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency_points
Date: March 2019
KernelVersion: 3.1.0 KernelVersion: 3.1.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Number of frequency points (steps) in the frequency sweep. Number of frequency points (steps) in the frequency sweep.
This value, in conjunction with the outY_freq_start and the This value, in conjunction with the
outY_freq_increment, determines the frequency sweep range out_altvoltageY_frequency_start and the
for the sweep operation. out_altvoltageY_frequency_increment, determines the frequency
sweep range for the sweep operation.
What: /sys/bus/iio/devices/iio:deviceX/outY_settling_cycles What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_settling_cycles
Date: March 2019
KernelVersion: 3.1.0 KernelVersion: 3.1.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
......
What: /sys/bus/iio/devices/iio:deviceX/start_cleaning What: /sys/bus/iio/devices/iio:deviceX/start_cleaning
Date: December 2018 Date: December 2018
KernelVersion: 4.22 KernelVersion: 5.0
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
Writing 1 starts sensor self cleaning. Internal fan accelerates Writing 1 starts sensor self cleaning. Internal fan accelerates
......
What: /sys/bus/iio/devices/iio:deviceX/fault_oc
KernelVersion: 5.1
Contact: linux-iio@vger.kernel.org
Description:
Open-circuit fault. The detection of open-circuit faults,
such as those caused by broken thermocouple wires.
Reading returns either '1' or '0'.
'1' = An open circuit such as broken thermocouple wires
has been detected.
'0' = No open circuit or broken thermocouple wires are detected
What: /sys/bus/iio/devices/iio:deviceX/fault_ovuv
KernelVersion: 5.1
Contact: linux-iio@vger.kernel.org
Description:
Overvoltage or Undervoltage Input Fault. The internal circuitry
is protected from excessive voltages applied to the thermocouple
cables by integrated MOSFETs at the T+ and T- inputs, and the
BIAS output. These MOSFETs turn off when the input voltage is
negative or greater than VDD.
Reading returns either '1' or '0'.
'1' = The input voltage is negative or greater than VDD.
'0' = The input voltage is positive and less than VDD (normal
state).
Kionix KXCJK-1013 Accelerometer device tree bindings
Required properties:
- compatible: Must be one of:
"kionix,kxcjk1013"
"kionix,kxcj91008"
"kionix,kxtj21009"
"kionix,kxtf9"
- reg: i2c slave address
Example:
kxtf9@f {
compatible = "kionix,kxtf9";
reg = <0x0F>;
};
* Analog Devices AD7170/AD7171/AD7780/AD7781
Data sheets:
- AD7170:
* https://www.analog.com/media/en/technical-documentation/data-sheets/AD7170.pdf
- AD7171:
* https://www.analog.com/media/en/technical-documentation/data-sheets/AD7171.pdf
- AD7780:
* https://www.analog.com/media/en/technical-documentation/data-sheets/ad7780.pdf
- AD7781:
* https://www.analog.com/media/en/technical-documentation/data-sheets/AD7781.pdf
Required properties:
- compatible: should be one of
* "adi,ad7170"
* "adi,ad7171"
* "adi,ad7780"
* "adi,ad7781"
- reg: spi chip select number for the device
- vref-supply: the regulator supply for the ADC reference voltage
Optional properties:
- powerdown-gpios: must be the device tree identifier of the PDRST pin. If
specified, it will be asserted during driver probe. As the
line is active high, it should be marked GPIO_ACTIVE_HIGH.
- adi,gain-gpios: must be the device tree identifier of the GAIN pin. Only for
the ad778x chips. If specified, it will be asserted during
driver probe. As the line is active low, it should be marked
GPIO_ACTIVE_LOW.
- adi,filter-gpios: must be the device tree identifier of the FILTER pin. Only
for the ad778x chips. If specified, it will be asserted
during driver probe. As the line is active low, it should be
marked GPIO_ACTIVE_LOW.
Example:
adc@0 {
compatible = "adi,ad7780";
reg = <0>;
vref-supply = <&vdd_supply>
powerdown-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
adi,gain-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
adi,filter-gpios = <&gpio 15 GPIO_ACTIVE_LOW>;
};
...@@ -9,6 +9,7 @@ Required properties: ...@@ -9,6 +9,7 @@ Required properties:
- "amlogic,meson-gxl-saradc" for GXL - "amlogic,meson-gxl-saradc" for GXL
- "amlogic,meson-gxm-saradc" for GXM - "amlogic,meson-gxm-saradc" for GXM
- "amlogic,meson-axg-saradc" for AXG - "amlogic,meson-axg-saradc" for AXG
- "amlogic,meson-g12a-saradc" for AXG
along with the generic "amlogic,meson-saradc" along with the generic "amlogic,meson-saradc"
- reg: the physical base address and length of the registers - reg: the physical base address and length of the registers
- interrupts: the interrupt indicating end of sampling - interrupts: the interrupt indicating end of sampling
......
...@@ -6,6 +6,10 @@ Required properties: ...@@ -6,6 +6,10 @@ Required properties:
region. region.
- interrupts: The ADC interrupt - interrupts: The ADC interrupt
Optional:
- vref-supply: The regulator supply ADC reference voltage, optional
for legacy reason, but highly encouraging to us in new device tree
Example: Example:
adc@40048000 { adc@40048000 {
...@@ -13,4 +17,5 @@ Example: ...@@ -13,4 +17,5 @@ Example:
reg = <0x40048000 0x1000>; reg = <0x40048000 0x1000>;
interrupt-parent = <&mic>; interrupt-parent = <&mic>;
interrupts = <39 0>; interrupts = <39 0>;
vref-supply = <&vcc>;
}; };
* Plantower PMS7003 particulate matter sensor * Plantower PMS7003 particulate matter sensor
Required properties: Required properties:
- compatible: must be "plantower,pms7003" - compatible: must one of:
"plantower,pms1003"
"plantower,pms3003"
"plantower,pms5003"
"plantower,pms6003"
"plantower,pms7003"
"plantower,pmsa003"
- vcc-supply: phandle to the regulator that provides power to the sensor - vcc-supply: phandle to the regulator that provides power to the sensor
Optional properties: Optional properties:
......
...@@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node. ...@@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node.
Required properties: Required properties:
- compatible: Must be "st,stm32-lptimer-counter". - compatible: Must be "st,stm32-lptimer-counter".
- pinctrl-names: Set to "default". - pinctrl-names: Set to "default". An additional "sleep" state can be
- pinctrl-0: List of phandles pointing to pin configuration nodes, defined to set pins in sleep state.
- pinctrl-n: List of phandles pointing to pin configuration nodes,
to set IN1/IN2 pins in mode of operation for Low-Power to set IN1/IN2 pins in mode of operation for Low-Power
Timer input on external pin. Timer input on external pin.
...@@ -21,7 +22,8 @@ Example: ...@@ -21,7 +22,8 @@ Example:
... ...
counter { counter {
compatible = "st,stm32-lptimer-counter"; compatible = "st,stm32-lptimer-counter";
pinctrl-names = "default"; pinctrl-names = "default", "sleep";
pinctrl-0 = <&lptim1_in_pins>; pinctrl-0 = <&lptim1_in_pins>;
pinctrl-1 = <&lptim1_sleep_in_pins>;
}; };
}; };
* Bosch BMG160 triaxial rotation sensor (gyroscope)
Required properties:
- compatible : should be "bosch,bmg160" or "bosch,bmi055_gyro"
- reg : the I2C address of the sensor (0x69)
Optional properties:
- interrupts : interrupt mapping for GPIO IRQ, it should by configured with
flags IRQ_TYPE_EDGE_RISING
Example:
bmg160@69 {
compatible = "bosch,bmg160";
reg = <0x69>;
interrupt-parent = <&gpio6>;
interrupts = <18 (IRQ_TYPE_EDGE_RISING)>;
};
Analog Devices ADIS16480 and similar IMUs
Required properties for the ADIS16480:
- compatible: Must be one of
* "adi,adis16375"
* "adi,adis16480"
* "adi,adis16485"
* "adi,adis16488"
* "adi,adis16495-1"
* "adi,adis16495-2"
* "adi,adis16495-3"
* "adi,adis16497-1"
* "adi,adis16497-2"
* "adi,adis16497-3"
- reg: SPI chip select number for the device
- spi-max-frequency: Max SPI frequency to use
see: Documentation/devicetree/bindings/spi/spi-bus.txt
- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt
- spi-cpol: See Documentation/devicetree/bindings/spi/spi-bus.txt
- interrupts: interrupt mapping for IRQ, accepted values are:
* IRQF_TRIGGER_RISING
* IRQF_TRIGGER_FALLING
Optional properties:
- interrupt-names: Data ready line selection. Valid values are:
* DIO1
* DIO2
* DIO3
* DIO4
If this field is left empty, DIO1 is assigned as default data ready
signal.
- reset-gpios: must be the device tree identifier of the RESET pin. As the line
is active low, it should be marked GPIO_ACTIVE_LOW.
- clocks: phandle to the external clock. Should be set according to
"clock-names".
If this field is left empty together with the "clock-names" field, then
the internal clock is used.
- clock-names: The name of the external clock to be used. Valid values are:
* sync: In sync mode, the internal clock is disabled and the frequency
of the external clock signal establishes therate of data
collection and processing. See Fig 14 and 15 in the datasheet.
The clock-frequency must be:
* 3000 to 4500 Hz for adis1649x devices.
* 700 to 2400 Hz for adis1648x devices.
* pps: In Pulse Per Second (PPS) Mode, the rate of data collection and
production is equal to the product of the external clock
frequency and the scale factor in the SYNC_SCALE register, see
Table 154 in the datasheet.
The clock-frequency must be:
* 1 to 128 Hz for adis1649x devices.
* This mode is not supported by adis1648x devices.
If this field is left empty together with the "clocks" field, then the
internal clock is used.
- adi,ext-clk-pin: The DIOx line to be used as an external clock input.
Valid values are:
* DIO1
* DIO2
* DIO3
* DIO4
Each DIOx pin supports only one function at a time (data ready line
selection or external clock input). When a single pin has two
two assignments, the enable bit for the lower priority function
automatically resets to zero (disabling the lower priority function).
Data ready has highest priority.
If this field is left empty, DIO2 is assigned as default external clock
input pin.
Example:
imu@0 {
compatible = "adi,adis16495-1";
reg = <0>;
spi-max-frequency = <3200000>;
spi-cpol;
spi-cpha;
interrupts = <25 IRQF_TRIGGER_FALLING>;
interrupt-parent = <&gpio>;
interrupt-names = "DIO2";
clocks = <&adis16495_sync>;
clock-names = "sync";
adi,ext-clk-pin = "DIO1";
};
...@@ -8,6 +8,8 @@ Required properties: ...@@ -8,6 +8,8 @@ Required properties:
"st,lsm6dsm" "st,lsm6dsm"
"st,ism330dlc" "st,ism330dlc"
"st,lsm6dso" "st,lsm6dso"
"st,asm330lhh"
"st,lsm6dsox"
- reg: i2c address of the sensor / spi cs line - reg: i2c address of the sensor / spi cs line
Optional properties: Optional properties:
......
VISHAY VCNL4000 - Ambient Light and proximity sensor
This driver supports the VCNL4000/10/20/40 and VCNL4200 chips
Required properties:
-compatible: must be one of :
vishay,vcnl4000
vishay,vcnl4010
vishay,vcnl4020
vishay,vcnl4040
vishay,vcnl4200
-reg: I2C address of the sensor, should be one from below based on the model:
0x13
0x51
0x60
Example:
light-sensor@51 {
compatible = "vishay,vcnl4200";
reg = <0x51>;
};
* Devantech SRF04 ultrasonic range finder
Bit-banging driver using two GPIOs
Required properties:
- compatible: Should be "devantech,srf04"
- trig-gpios: Definition of the GPIO for the triggering (output)
This GPIO is set for about 10 us by the driver to tell the
device it should initiate the measurement cycle.
- echo-gpios: Definition of the GPIO for the echo (input)
This GPIO is set by the device as soon as an ultrasonic
burst is sent out and reset when the first echo is
received.
Thus this GPIO is set while the ultrasonic waves are doing
one round trip.
It needs to be an GPIO which is able to deliver an
interrupt because the time between two interrupts is
measured in the driver.
See Documentation/devicetree/bindings/gpio/gpio.txt for
information on how to specify a consumer gpio.
Example:
srf04@0 {
compatible = "devantech,srf04";
trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/devantech-srf04.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Devantech SRF04 ultrasonic range finder
maintainers:
- Andreas Klinger <ak@it-klinger.de>
description: |
Bit-banging driver using two GPIOs:
- trigger-gpio is raised by the driver to start sending out an ultrasonic
burst
- echo-gpio is held high by the sensor after sending ultrasonic burst
until it is received once again
Specifications about the driver can be found at:
http://www.robot-electronics.co.uk/htm/srf04tech.htm
properties:
compatible:
items:
- const: devantech,srf04
trig-gpios:
description:
Definition of the GPIO for the triggering (output) This GPIO is set
for about 10 us by the driver to tell the device it should initiate
the measurement cycle.
maxItems: 1
echo-gpios:
description:
Definition of the GPIO for the echo (input)
This GPIO is set by the device as soon as an ultrasonic burst is sent
out and reset when the first echo is received.
Thus this GPIO is set while the ultrasonic waves are doing one round
trip.
It needs to be an GPIO which is able to deliver an interrupt because
the time between two interrupts is measured in the driver.
See Documentation/devicetree/bindings/gpio/gpio.txt for information
on how to specify a consumer gpio.
maxItems: 1
required:
- compatible
- trig-gpios
- echo-gpios
examples:
- |
#include <dt-bindings/gpio/gpio.h>
proximity {
compatible = "devantech,srf04";
trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
};
* MaxBotix I2CXL-MaxSonar ultrasonic distance sensor of type mb1202,
mb1212, mb1222, mb1232, mb1242, mb7040 or mb7137 using the i2c interface
for ranging
Required properties:
- compatible: "maxbotix,mb1202",
"maxbotix,mb1212",
"maxbotix,mb1222",
"maxbotix,mb1232",
"maxbotix,mb1242",
"maxbotix,mb7040" or
"maxbotix,mb7137"
- reg: i2c address of the device, see also i2c/i2c.txt
Optional properties:
- interrupts: Interrupt used to announce the preceding reading
request has finished and that data is available.
If no interrupt is specified the device driver
falls back to wait a fixed amount of time until
data can be retrieved.
Example:
proximity@70 {
compatible = "maxbotix,mb1232";
reg = <0x70>;
interrupt-parent = <&gpio2>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
};
Maxim MAX31856 thermocouple support
https://datasheets.maximintegrated.com/en/ds/MAX31856.pdf
Optional property:
- thermocouple-type: Type of thermocouple (THERMOCOUPLE_TYPE_K if
omitted). Supported types are B, E, J, K, N, R, S, T.
Required properties:
- compatible: must be "maxim,max31856"
- reg: SPI chip select number for the device
- spi-max-frequency: As per datasheet max. supported freq is 5000000
- spi-cpha: must be defined for max31856 to enable SPI mode 1
Refer to spi/spi-bus.txt for generic SPI slave bindings.
Example:
temp-sensor@0 {
compatible = "maxim,max31856";
reg = <0>;
spi-max-frequency = <5000000>;
spi-cpha;
thermocouple-type = <THERMOCOUPLE_TYPE_K>;
};
If the temperature sensor device can be configured to use some specific
thermocouple type, you can use the defined types provided in the file
"include/dt-bindings/iio/temperature/thermocouple.h".
Property:
thermocouple-type: A single cell representing the type of the thermocouple
used by the device.
...@@ -210,6 +210,7 @@ kiebackpeter Kieback & Peter GmbH ...@@ -210,6 +210,7 @@ kiebackpeter Kieback & Peter GmbH
kinetic Kinetic Technologies kinetic Kinetic Technologies
kingdisplay King & Display Technology Co., Ltd. kingdisplay King & Display Technology Co., Ltd.
kingnovel Kingnovel Technology Co., Ltd. kingnovel Kingnovel Technology Co., Ltd.
kionix Kionix, Inc.
koe Kaohsiung Opto-Electronics Inc. koe Kaohsiung Opto-Electronics Inc.
kosagi Sutajio Ko-Usagi PTE Ltd. kosagi Sutajio Ko-Usagi PTE Ltd.
kyo Kyocera Corporation kyo Kyocera Corporation
...@@ -233,6 +234,7 @@ lsi LSI Corp. (LSI Logic) ...@@ -233,6 +234,7 @@ lsi LSI Corp. (LSI Logic)
lwn Liebherr-Werk Nenzing GmbH lwn Liebherr-Werk Nenzing GmbH
macnica Macnica Americas macnica Macnica Americas
marvell Marvell Technology Group Ltd. marvell Marvell Technology Group Ltd.
maxbotix MaxBotix Inc.
maxim Maxim Integrated Products maxim Maxim Integrated Products
mbvl Mobiveil Inc. mbvl Mobiveil Inc.
mcube mCube mcube mCube
......
...@@ -868,7 +868,7 @@ L: linux-iio@vger.kernel.org ...@@ -868,7 +868,7 @@ L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers W: http://ez.analog.com/community/linux-device-drivers
S: Supported S: Supported
F: drivers/iio/adc/ad7606.c F: drivers/iio/adc/ad7606.c
F: Documentation/devicetree/bindings/iio/adc/ad7606.txt F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.txt
ANALOG DEVICES INC AD7768-1 DRIVER ANALOG DEVICES INC AD7768-1 DRIVER
M: Stefan Popa <stefan.popa@analog.com> M: Stefan Popa <stefan.popa@analog.com>
...@@ -950,6 +950,7 @@ F: drivers/dma/dma-axi-dmac.c ...@@ -950,6 +950,7 @@ F: drivers/dma/dma-axi-dmac.c
ANALOG DEVICES INC IIO DRIVERS ANALOG DEVICES INC IIO DRIVERS
M: Lars-Peter Clausen <lars@metafoo.de> M: Lars-Peter Clausen <lars@metafoo.de>
M: Michael Hennerich <Michael.Hennerich@analog.com> M: Michael Hennerich <Michael.Hennerich@analog.com>
M: Stefan Popa <stefan.popa@analog.com>
W: http://wiki.analog.com/ W: http://wiki.analog.com/
W: http://ez.analog.com/community/linux-device-drivers W: http://ez.analog.com/community/linux-device-drivers
S: Supported S: Supported
...@@ -9406,6 +9407,13 @@ S: Maintained ...@@ -9406,6 +9407,13 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/max9860.txt F: Documentation/devicetree/bindings/sound/max9860.txt
F: sound/soc/codecs/max9860.* F: sound/soc/codecs/max9860.*
MAXBOTIX ULTRASONIC RANGER IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt
F: drivers/iio/proximity/mb1232.c
MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
M: Javier Martinez Canillas <javier@dowhile0.org> M: Javier Martinez Canillas <javier@dowhile0.org>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
......
...@@ -39,28 +39,28 @@ config IIO_TRIGGER ...@@ -39,28 +39,28 @@ config IIO_TRIGGER
data now' interrupt. data now' interrupt.
config IIO_CONSUMERS_PER_TRIGGER config IIO_CONSUMERS_PER_TRIGGER
int "Maximum number of consumers per trigger" int "Maximum number of consumers per trigger"
depends on IIO_TRIGGER depends on IIO_TRIGGER
default "2" default "2"
help help
This value controls the maximum number of consumers that a This value controls the maximum number of consumers that a
given trigger may handle. Default is 2. given trigger may handle. Default is 2.
config IIO_SW_DEVICE config IIO_SW_DEVICE
tristate "Enable software IIO device support" tristate "Enable software IIO device support"
select IIO_CONFIGFS select IIO_CONFIGFS
help help
Provides IIO core support for software devices. A software Provides IIO core support for software devices. A software
device can be created via configfs or directly by a driver device can be created via configfs or directly by a driver
using the API provided. using the API provided.
config IIO_SW_TRIGGER config IIO_SW_TRIGGER
tristate "Enable software triggers support" tristate "Enable software triggers support"
select IIO_CONFIGFS select IIO_CONFIGFS
help help
Provides IIO core support for software triggers. A software Provides IIO core support for software triggers. A software
trigger can be created via configfs or directly by a driver trigger can be created via configfs or directly by a driver
using the API provided. using the API provided.
config IIO_TRIGGERED_EVENT config IIO_TRIGGERED_EVENT
tristate tristate
......
...@@ -6,28 +6,28 @@ ...@@ -6,28 +6,28 @@
menu "Accelerometers" menu "Accelerometers"
config ADIS16201 config ADIS16201
tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI depends on SPI
select IIO_ADIS_LIB select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say Y here to build support for Analog Devices adis16201 dual-axis Say Y here to build support for Analog Devices adis16201 dual-axis
digital inclinometer and accelerometer. digital inclinometer and accelerometer.
To compile this driver as a module, say M here: the module will To compile this driver as a module, say M here: the module will
be called adis16201. be called adis16201.
config ADIS16209 config ADIS16209
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
depends on SPI depends on SPI
select IIO_ADIS_LIB select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help help
Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer
and accelerometer. and accelerometer.
To compile this driver as a module, say M here: the module will be To compile this driver as a module, say M here: the module will be
called adis16209. called adis16209.
config ADXL345 config ADXL345
tristate tristate
...@@ -100,16 +100,16 @@ config BMA180 ...@@ -100,16 +100,16 @@ config BMA180
module will be called bma180. module will be called bma180.
config BMA220 config BMA220
tristate "Bosch BMA220 3-Axis Accelerometer Driver" tristate "Bosch BMA220 3-Axis Accelerometer Driver"
depends on SPI depends on SPI
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
help help
Say yes here to add support for the Bosch BMA220 triaxial Say yes here to add support for the Bosch BMA220 triaxial
acceleration sensor. acceleration sensor.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called bma220_spi. module will be called bma220_spi.
config BMC150_ACCEL config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver" tristate "Bosch BMC150 Accelerometer Driver"
......
...@@ -116,6 +116,7 @@ struct bma180_data { ...@@ -116,6 +116,7 @@ struct bma180_data {
struct i2c_client *client; struct i2c_client *client;
struct iio_trigger *trig; struct iio_trigger *trig;
const struct bma180_part_info *part_info; const struct bma180_part_info *part_info;
struct iio_mount_matrix orientation;
struct mutex mutex; struct mutex mutex;
bool sleep_state; bool sleep_state;
int scale; int scale;
...@@ -561,6 +562,15 @@ static int bma180_set_power_mode(struct iio_dev *indio_dev, ...@@ -561,6 +562,15 @@ static int bma180_set_power_mode(struct iio_dev *indio_dev,
return ret; return ret;
} }
static const struct iio_mount_matrix *
bma180_accel_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bma180_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_enum bma180_power_mode_enum = { static const struct iio_enum bma180_power_mode_enum = {
.items = bma180_power_modes, .items = bma180_power_modes,
.num_items = ARRAY_SIZE(bma180_power_modes), .num_items = ARRAY_SIZE(bma180_power_modes),
...@@ -571,7 +581,8 @@ static const struct iio_enum bma180_power_mode_enum = { ...@@ -571,7 +581,8 @@ static const struct iio_enum bma180_power_mode_enum = {
static const struct iio_chan_spec_ext_info bma180_ext_info[] = { static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
IIO_ENUM("power_mode", true, &bma180_power_mode_enum), IIO_ENUM("power_mode", true, &bma180_power_mode_enum),
IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum), IIO_ENUM_AVAILABLE("power_mode", &bma180_power_mode_enum),
{ }, IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma180_accel_get_mount_matrix),
{ }
}; };
#define BMA180_ACC_CHANNEL(_axis, _bits) { \ #define BMA180_ACC_CHANNEL(_axis, _bits) { \
...@@ -722,6 +733,11 @@ static int bma180_probe(struct i2c_client *client, ...@@ -722,6 +733,11 @@ static int bma180_probe(struct i2c_client *client,
chip = id->driver_data; chip = id->driver_data;
data->part_info = &bma180_part_info[chip]; data->part_info = &bma180_part_info[chip];
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
&data->orientation);
if (ret)
return ret;
ret = data->part_info->chip_config(data); ret = data->part_info->chip_config(data);
if (ret < 0) if (ret < 0)
goto err_chip_disable; goto err_chip_disable;
......
...@@ -204,6 +204,7 @@ struct bmc150_accel_data { ...@@ -204,6 +204,7 @@ struct bmc150_accel_data {
int ev_enable_state; int ev_enable_state;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
const struct bmc150_accel_chip_info *chip_info; const struct bmc150_accel_chip_info *chip_info;
struct iio_mount_matrix orientation;
}; };
static const struct { static const struct {
...@@ -796,6 +797,20 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev, ...@@ -796,6 +797,20 @@ static ssize_t bmc150_accel_get_fifo_state(struct device *dev,
return sprintf(buf, "%d\n", state); return sprintf(buf, "%d\n", state);
} }
static const struct iio_mount_matrix *
bmc150_accel_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info bmc150_accel_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_accel_get_mount_matrix),
{ }
};
static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
static IIO_CONST_ATTR(hwfifo_watermark_max, static IIO_CONST_ATTR(hwfifo_watermark_max,
__stringify(BMC150_ACCEL_FIFO_LENGTH)); __stringify(BMC150_ACCEL_FIFO_LENGTH));
...@@ -978,6 +993,7 @@ static const struct iio_event_spec bmc150_accel_event = { ...@@ -978,6 +993,7 @@ static const struct iio_event_spec bmc150_accel_event = {
.shift = 16 - (bits), \ .shift = 16 - (bits), \
.endianness = IIO_LE, \ .endianness = IIO_LE, \
}, \ }, \
.ext_info = bmc150_accel_ext_info, \
.event_spec = &bmc150_accel_event, \ .event_spec = &bmc150_accel_event, \
.num_event_specs = 1 \ .num_event_specs = 1 \
} }
...@@ -1555,6 +1571,11 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, ...@@ -1555,6 +1571,11 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->regmap = regmap; data->regmap = regmap;
ret = iio_read_mount_matrix(dev, "mount-matrix",
&data->orientation);
if (ret)
return ret;
ret = bmc150_accel_chip_init(data); ret = bmc150_accel_chip_init(data);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Driver for older Chrome OS EC accelerometer * Driver for older Chrome OS EC accelerometer
* *
* Copyright 2017 Google, Inc * Copyright 2017 Google, Inc
* *
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This driver uses the memory mapper cros-ec interface to communicate * This driver uses the memory mapper cros-ec interface to communicate
* with the Chrome OS EC about accelerometer data. * with the Chrome OS EC about accelerometer data.
* Accelerometer access is presented through iio sysfs. * Accelerometer access is presented through iio sysfs.
...@@ -29,7 +21,6 @@ ...@@ -29,7 +21,6 @@
#include <linux/mfd/cros_ec_commands.h> #include <linux/mfd/cros_ec_commands.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#define DRV_NAME "cros-ec-accel-legacy" #define DRV_NAME "cros-ec-accel-legacy"
...@@ -353,7 +344,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) ...@@ -353,7 +344,7 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
struct cros_ec_accel_legacy_state *state; struct cros_ec_accel_legacy_state *state;
int ret, i; int ret;
if (!ec || !ec->ec_dev) { if (!ec || !ec->ec_dev) {
dev_warn(&pdev->dev, "No EC device found.\n"); dev_warn(&pdev->dev, "No EC device found.\n");
...@@ -381,20 +372,17 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev) ...@@ -381,20 +372,17 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
* Present the channel using HTML5 standard: * Present the channel using HTML5 standard:
* need to invert X and Y and invert some lid axis. * need to invert X and Y and invert some lid axis.
*/ */
for (i = X ; i < MAX_AXIS; i++) { ec_accel_channels[X].scan_index = Y;
switch (i) { ec_accel_channels[Y].scan_index = X;
case X: ec_accel_channels[Z].scan_index = Z;
ec_accel_channels[X].scan_index = Y;
case Y: state->sign[Y] = 1;
ec_accel_channels[Y].scan_index = X;
case Z: if (state->sensor_num == MOTIONSENSE_LOC_LID)
ec_accel_channels[Z].scan_index = Z; state->sign[X] = state->sign[Z] = -1;
} else
if (state->sensor_num == MOTIONSENSE_LOC_LID && i != Y) state->sign[X] = state->sign[Z] = 1;
state->sign[i] = -1;
else
state->sign[i] = 1;
}
indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels); indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels);
indio_dev->dev.parent = &pdev->dev; indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &cros_ec_accel_legacy_info; indio_dev->info = &cros_ec_accel_legacy_info;
...@@ -419,5 +407,5 @@ module_platform_driver(cros_ec_accel_platform_driver); ...@@ -419,5 +407,5 @@ module_platform_driver(cros_ec_accel_platform_driver);
MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver"); MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver");
MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME); MODULE_ALIAS("platform:" DRV_NAME);
...@@ -1510,10 +1510,20 @@ static const struct i2c_device_id kxcjk1013_id[] = { ...@@ -1510,10 +1510,20 @@ static const struct i2c_device_id kxcjk1013_id[] = {
MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); MODULE_DEVICE_TABLE(i2c, kxcjk1013_id);
static const struct of_device_id kxcjk1013_of_match[] = {
{ .compatible = "kionix,kxcjk1013", },
{ .compatible = "kionix,kxcj91008", },
{ .compatible = "kionix,kxtj21009", },
{ .compatible = "kionix,kxtf9", },
{ }
};
MODULE_DEVICE_TABLE(of, kxcjk1013_of_match);
static struct i2c_driver kxcjk1013_driver = { static struct i2c_driver kxcjk1013_driver = {
.driver = { .driver = {
.name = KXCJK1013_DRV_NAME, .name = KXCJK1013_DRV_NAME,
.acpi_match_table = ACPI_PTR(kx_acpi_match), .acpi_match_table = ACPI_PTR(kx_acpi_match),
.of_match_table = kxcjk1013_of_match,
.pm = &kxcjk1013_pm_ops, .pm = &kxcjk1013_pm_ops,
}, },
.probe = kxcjk1013_probe, .probe = kxcjk1013_probe,
......
...@@ -420,9 +420,7 @@ int kxsd9_common_probe(struct device *dev, ...@@ -420,9 +420,7 @@ int kxsd9_common_probe(struct device *dev,
indio_dev->available_scan_masks = kxsd9_scan_masks; indio_dev->available_scan_masks = kxsd9_scan_masks;
/* Read the mounting matrix, if present */ /* Read the mounting matrix, if present */
ret = of_iio_read_mount_matrix(dev, ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
"mount-matrix",
&st->orientation);
if (ret) if (ret)
return ret; return ret;
......
...@@ -1580,7 +1580,7 @@ static int mma8452_probe(struct i2c_client *client, ...@@ -1580,7 +1580,7 @@ static int mma8452_probe(struct i2c_client *client,
case FXLS8471_DEVICE_ID: case FXLS8471_DEVICE_ID:
if (ret == data->chip_info->chip_id) if (ret == data->chip_info->chip_id)
break; break;
/* else: fall through */ /* fall through */
default: default:
ret = -ENODEV; ret = -ENODEV;
goto disable_regulators; goto disable_regulators;
......
...@@ -992,7 +992,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev, ...@@ -992,7 +992,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
goto out; goto out;
val = elements[i].integer.value; val = elements[i].integer.value;
if (val < 0 || val > 2) if (val > 2)
goto out; goto out;
/* Avoiding full matrix multiplication, we simply reorder the /* Avoiding full matrix multiplication, we simply reorder the
......
...@@ -124,6 +124,18 @@ config AD7768_1 ...@@ -124,6 +124,18 @@ config AD7768_1
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called ad7768-1. called ad7768-1.
config AD7780
tristate "Analog Devices AD7780 and similar ADCs driver"
depends on SPI
depends on GPIOLIB || COMPILE_TEST
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7170, AD7171,
AD7780 and AD7781 SPI analog to digital converters (ADC).
To compile this driver as a module, choose M here: the
module will be called ad7780.
config AD7791 config AD7791
tristate "Analog Devices AD7791 ADC driver" tristate "Analog Devices AD7791 ADC driver"
depends on SPI depends on SPI
...@@ -390,7 +402,7 @@ config HX711 ...@@ -390,7 +402,7 @@ config HX711
This driver uses two GPIOs, one acts as the clock and controls the This driver uses two GPIOs, one acts as the clock and controls the
channel selection and gain, the other one is used for the measurement channel selection and gain, the other one is used for the measurement
data data
Currently the raw value is read from the chip and delivered. Currently the raw value is read from the chip and delivered.
To get an actual weight one needs to subtract the To get an actual weight one needs to subtract the
...@@ -585,17 +597,17 @@ config MCP3911 ...@@ -585,17 +597,17 @@ config MCP3911
called mcp3911. called mcp3911.
config MEDIATEK_MT6577_AUXADC config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver" tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM
help help
Say yes here to enable support for MediaTek mt65xx AUXADC. Say yes here to enable support for MediaTek mt65xx AUXADC.
The driver supports immediate mode operation to read from one of sixteen The driver supports immediate mode operation to read from one of sixteen
channels (external or internal). channels (external or internal).
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called mt6577_auxadc. called mt6577_auxadc.
config MEN_Z188_ADC config MEN_Z188_ADC
tristate "MEN 16z188 ADC IP Core support" tristate "MEN 16z188 ADC IP Core support"
......
...@@ -16,6 +16,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
obj-$(CONFIG_AD7606) += ad7606.o obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7766) += ad7766.o
obj-$(CONFIG_AD7768_1) += ad7768-1.o obj-$(CONFIG_AD7768_1) += ad7768-1.o
obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7887) += ad7887.o
......
...@@ -411,7 +411,7 @@ static int ad7124_init_channel_vref(struct ad7124_state *st, ...@@ -411,7 +411,7 @@ static int ad7124_init_channel_vref(struct ad7124_state *st,
dev_err(&st->sd.spi->dev, dev_err(&st->sd.spi->dev,
"Error, trying to use external voltage reference without a %s regulator.\n", "Error, trying to use external voltage reference without a %s regulator.\n",
ad7124_ref_names[refsel]); ad7124_ref_names[refsel]);
return PTR_ERR(st->vref[refsel]); return PTR_ERR(st->vref[refsel]);
} }
st->channel_config[channel_number].vref_mv = st->channel_config[channel_number].vref_mv =
regulator_get_voltage(st->vref[refsel]); regulator_get_voltage(st->vref[refsel]);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* AD7170/AD7171 and AD7780/AD7781 SPI ADC driver * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver
* *
* Copyright 2011 Analog Devices Inc. * Copyright 2011 Analog Devices Inc.
* Copyright 2019 Renato Lui Geh
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/bits.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
...@@ -27,16 +29,25 @@ ...@@ -27,16 +29,25 @@
#define AD7780_ID1 BIT(4) #define AD7780_ID1 BIT(4)
#define AD7780_ID0 BIT(3) #define AD7780_ID0 BIT(3)
#define AD7780_GAIN BIT(2) #define AD7780_GAIN BIT(2)
#define AD7780_PAT1 BIT(1)
#define AD7780_PAT0 BIT(0)
#define AD7780_PATTERN (AD7780_PAT0) #define AD7170_ID 0
#define AD7780_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1) #define AD7171_ID 1
#define AD7780_ID 1
#define AD7781_ID 0
#define AD7170_PAT2 BIT(2) #define AD7780_ID_MASK (AD7780_ID0 | AD7780_ID1)
#define AD7170_PATTERN (AD7780_PAT0 | AD7170_PAT2) #define AD7780_PATTERN_GOOD 1
#define AD7170_PATTERN_MASK (AD7780_PAT0 | AD7780_PAT1 | AD7170_PAT2) #define AD7780_PATTERN_MASK GENMASK(1, 0)
#define AD7170_PATTERN_GOOD 5
#define AD7170_PATTERN_MASK GENMASK(2, 0)
#define AD7780_GAIN_MIDPOINT 64
#define AD7780_FILTER_MIDPOINT 13350
static const unsigned int ad778x_gain[2] = { 1, 128 };
static const unsigned int ad778x_odr_avail[2] = { 10000, 16700 };
struct ad7780_chip_info { struct ad7780_chip_info {
struct iio_chan_spec channel; struct iio_chan_spec channel;
...@@ -49,7 +60,11 @@ struct ad7780_state { ...@@ -49,7 +60,11 @@ struct ad7780_state {
const struct ad7780_chip_info *chip_info; const struct ad7780_chip_info *chip_info;
struct regulator *reg; struct regulator *reg;
struct gpio_desc *powerdown_gpio; struct gpio_desc *powerdown_gpio;
unsigned int gain; struct gpio_desc *gain_gpio;
struct gpio_desc *filter_gpio;
unsigned int gain;
unsigned int odr;
unsigned int int_vref_mv;
struct ad_sigma_delta sd; struct ad_sigma_delta sd;
}; };
...@@ -103,17 +118,69 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, ...@@ -103,17 +118,69 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
voltage_uv = regulator_get_voltage(st->reg); voltage_uv = regulator_get_voltage(st->reg);
if (voltage_uv < 0) if (voltage_uv < 0)
return voltage_uv; return voltage_uv;
*val = (voltage_uv / 1000) * st->gain; voltage_uv /= 1000;
*val = voltage_uv * st->gain;
*val2 = chan->scan_type.realbits - 1; *val2 = chan->scan_type.realbits - 1;
st->int_vref_mv = voltage_uv;
return IIO_VAL_FRACTIONAL_LOG2; return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = -(1 << (chan->scan_type.realbits - 1)); *val = -(1 << (chan->scan_type.realbits - 1));
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->odr;
return IIO_VAL_INT;
default:
break;
} }
return -EINVAL; return -EINVAL;
} }
static int ad7780_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long m)
{
struct ad7780_state *st = iio_priv(indio_dev);
const struct ad7780_chip_info *chip_info = st->chip_info;
unsigned long long vref;
unsigned int full_scale, gain;
if (!chip_info->is_ad778x)
return -EINVAL;
switch (m) {
case IIO_CHAN_INFO_SCALE:
if (val != 0)
return -EINVAL;
vref = st->int_vref_mv * 1000000LL;
full_scale = 1 << (chip_info->channel.scan_type.realbits - 1);
gain = DIV_ROUND_CLOSEST_ULL(vref, full_scale);
gain = DIV_ROUND_CLOSEST(gain, val2);
st->gain = gain;
if (gain < AD7780_GAIN_MIDPOINT)
gain = 0;
else
gain = 1;
gpiod_set_value(st->gain_gpio, gain);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (1000*val + val2/1000 < AD7780_FILTER_MIDPOINT)
val = 0;
else
val = 1;
st->odr = ad778x_odr_avail[val];
gpiod_set_value(st->filter_gpio, val);
break;
default:
break;
}
return 0;
}
static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
unsigned int raw_sample) unsigned int raw_sample)
{ {
...@@ -125,10 +192,8 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, ...@@ -125,10 +192,8 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
return -EIO; return -EIO;
if (chip_info->is_ad778x) { if (chip_info->is_ad778x) {
if (raw_sample & AD7780_GAIN) st->gain = ad778x_gain[raw_sample & AD7780_GAIN];
st->gain = 1; st->odr = ad778x_odr_avail[raw_sample & AD7780_FILTER];
else
st->gain = 128;
} }
return 0; return 0;
...@@ -141,30 +206,32 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { ...@@ -141,30 +206,32 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
}; };
#define AD7780_CHANNEL(bits, wordsize) \ #define AD7780_CHANNEL(bits, wordsize) \
AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits) AD_SD_CHANNEL(1, 0, 0, bits, 32, (wordsize) - (bits))
#define AD7170_CHANNEL(bits, wordsize) \
AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, (wordsize) - (bits))
static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
[ID_AD7170] = { [ID_AD7170] = {
.channel = AD7780_CHANNEL(12, 24), .channel = AD7170_CHANNEL(12, 24),
.pattern = AD7170_PATTERN, .pattern = AD7170_PATTERN_GOOD,
.pattern_mask = AD7170_PATTERN_MASK, .pattern_mask = AD7170_PATTERN_MASK,
.is_ad778x = false, .is_ad778x = false,
}, },
[ID_AD7171] = { [ID_AD7171] = {
.channel = AD7780_CHANNEL(16, 24), .channel = AD7170_CHANNEL(16, 24),
.pattern = AD7170_PATTERN, .pattern = AD7170_PATTERN_GOOD,
.pattern_mask = AD7170_PATTERN_MASK, .pattern_mask = AD7170_PATTERN_MASK,
.is_ad778x = false, .is_ad778x = false,
}, },
[ID_AD7780] = { [ID_AD7780] = {
.channel = AD7780_CHANNEL(24, 32), .channel = AD7780_CHANNEL(24, 32),
.pattern = AD7780_PATTERN, .pattern = AD7780_PATTERN_GOOD,
.pattern_mask = AD7780_PATTERN_MASK, .pattern_mask = AD7780_PATTERN_MASK,
.is_ad778x = true, .is_ad778x = true,
}, },
[ID_AD7781] = { [ID_AD7781] = {
.channel = AD7780_CHANNEL(20, 32), .channel = AD7780_CHANNEL(20, 32),
.pattern = AD7780_PATTERN, .pattern = AD7780_PATTERN_GOOD,
.pattern_mask = AD7780_PATTERN_MASK, .pattern_mask = AD7780_PATTERN_MASK,
.is_ad778x = true, .is_ad778x = true,
}, },
...@@ -172,8 +239,47 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { ...@@ -172,8 +239,47 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
static const struct iio_info ad7780_info = { static const struct iio_info ad7780_info = {
.read_raw = ad7780_read_raw, .read_raw = ad7780_read_raw,
.write_raw = ad7780_write_raw,
}; };
static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st)
{
int ret;
st->powerdown_gpio = devm_gpiod_get_optional(dev,
"powerdown",
GPIOD_OUT_LOW);
if (IS_ERR(st->powerdown_gpio)) {
ret = PTR_ERR(st->powerdown_gpio);
dev_err(dev, "Failed to request powerdown GPIO: %d\n", ret);
return ret;
}
if (!st->chip_info->is_ad778x)
return 0;
st->gain_gpio = devm_gpiod_get_optional(dev,
"adi,gain",
GPIOD_OUT_HIGH);
if (IS_ERR(st->gain_gpio)) {
ret = PTR_ERR(st->gain_gpio);
dev_err(dev, "Failed to request gain GPIO: %d\n", ret);
return ret;
}
st->filter_gpio = devm_gpiod_get_optional(dev,
"adi,filter",
GPIOD_OUT_HIGH);
if (IS_ERR(st->filter_gpio)) {
ret = PTR_ERR(st->filter_gpio);
dev_err(dev, "Failed to request filter GPIO: %d\n", ret);
return ret;
}
return 0;
}
static int ad7780_probe(struct spi_device *spi) static int ad7780_probe(struct spi_device *spi)
{ {
struct ad7780_state *st; struct ad7780_state *st;
...@@ -189,16 +295,6 @@ static int ad7780_probe(struct spi_device *spi) ...@@ -189,16 +295,6 @@ static int ad7780_probe(struct spi_device *spi)
ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info);
st->reg = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
return ret;
}
st->chip_info = st->chip_info =
&ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
...@@ -211,14 +307,18 @@ static int ad7780_probe(struct spi_device *spi) ...@@ -211,14 +307,18 @@ static int ad7780_probe(struct spi_device *spi)
indio_dev->num_channels = 1; indio_dev->num_channels = 1;
indio_dev->info = &ad7780_info; indio_dev->info = &ad7780_info;
st->powerdown_gpio = devm_gpiod_get_optional(&spi->dev, ret = ad7780_init_gpios(&spi->dev, st);
"powerdown", if (ret)
GPIOD_OUT_LOW); goto error_cleanup_buffer_and_trigger;
if (IS_ERR(st->powerdown_gpio)) {
ret = PTR_ERR(st->powerdown_gpio); st->reg = devm_regulator_get(&spi->dev, "avdd");
dev_err(&spi->dev, "Failed to request powerdown GPIO: %d\n", if (IS_ERR(st->reg))
ret); return PTR_ERR(st->reg);
goto error_disable_reg;
ret = regulator_enable(st->reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
return ret;
} }
ret = ad_sd_setup_buffer_and_trigger(indio_dev); ret = ad_sd_setup_buffer_and_trigger(indio_dev);
......
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
#include <linux/iio/trigger_consumer.h> #include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#define AD7923_WRITE_CR (1 << 11) /* write control register */ #define AD7923_WRITE_CR BIT(11) /* write control register */
#define AD7923_RANGE (1 << 1) /* range to REFin */ #define AD7923_RANGE BIT(1) /* range to REFin */
#define AD7923_CODING (1 << 0) /* coding is straight binary */ #define AD7923_CODING BIT(0) /* coding is straight binary */
#define AD7923_PM_MODE_AS (1) /* auto shutdown */ #define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */ #define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */ #define AD7923_PM_MODE_OPS (3) /* normal operation */
...@@ -40,16 +40,16 @@ ...@@ -40,16 +40,16 @@
#define AD7923_MAX_CHAN 4 #define AD7923_MAX_CHAN 4
#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */ #define AD7923_PM_MODE_WRITE(mode) ((mode) << 4) /* write mode */
#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */ #define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */
#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \ #define AD7923_SEQUENCE_WRITE(sequence) ((((sequence) & 1) << 3) \
+ ((sequence & 2) << 9)) + (((sequence) & 2) << 9))
/* write sequence fonction */ /* write sequence fonction */
/* left shift for CR : bit 11 transmit in first */ /* left shift for CR : bit 11 transmit in first */
#define AD7923_SHIFT_REGISTER 4 #define AD7923_SHIFT_REGISTER 4
/* val = value, dec = left shift, bits = number of bits of the mask */ /* val = value, dec = left shift, bits = number of bits of the mask */
#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1)) #define EXTRACT(val, dec, bits) (((val) >> (dec)) & ((1 << (bits)) - 1))
struct ad7923_state { struct ad7923_state {
struct spi_device *spi; struct spi_device *spi;
...@@ -130,7 +130,7 @@ static const struct ad7923_chip_info ad7923_chip_info[] = { ...@@ -130,7 +130,7 @@ static const struct ad7923_chip_info ad7923_chip_info[] = {
* ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask * ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask
**/ **/
static int ad7923_update_scan_mode(struct iio_dev *indio_dev, static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *active_scan_mask) const unsigned long *active_scan_mask)
{ {
struct ad7923_state *st = iio_priv(indio_dev); struct ad7923_state *st = iio_priv(indio_dev);
int i, cmd, len; int i, cmd, len;
...@@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p) ...@@ -181,7 +181,7 @@ static irqreturn_t ad7923_trigger_handler(int irq, void *p)
goto done; goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns(indio_dev)); iio_get_time_ns(indio_dev));
done: done:
iio_trigger_notify_done(indio_dev->trig); iio_trigger_notify_done(indio_dev->trig);
...@@ -272,7 +272,7 @@ static int ad7923_probe(struct spi_device *spi) ...@@ -272,7 +272,7 @@ static int ad7923_probe(struct spi_device *spi)
int ret; int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) if (!indio_dev)
return -ENOMEM; return -ENOMEM;
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
...@@ -314,7 +314,7 @@ static int ad7923_probe(struct spi_device *spi) ...@@ -314,7 +314,7 @@ static int ad7923_probe(struct spi_device *spi)
return ret; return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL, ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad7923_trigger_handler, NULL); &ad7923_trigger_handler, NULL);
if (ret) if (ret)
goto error_disable_reg; goto error_disable_reg;
......
...@@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, ...@@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
struct spi_transfer t = { struct spi_transfer t = {
.tx_buf = data, .tx_buf = data,
.len = size + 1, .len = size + 1,
.cs_change = sigma_delta->bus_locked, .cs_change = sigma_delta->keep_cs_asserted,
}; };
struct spi_message m; struct spi_message m;
int ret; int ret;
...@@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, ...@@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
spi_bus_lock(sigma_delta->spi->master); spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true; sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
reinit_completion(&sigma_delta->completion); reinit_completion(&sigma_delta->completion);
ret = ad_sigma_delta_set_mode(sigma_delta, mode); ret = ad_sigma_delta_set_mode(sigma_delta, mode);
...@@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, ...@@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
ret = 0; ret = 0;
} }
out: out:
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false; sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master); spi_bus_unlock(sigma_delta->spi->master);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
return ret; return ret;
} }
...@@ -289,6 +291,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ...@@ -289,6 +291,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
spi_bus_lock(sigma_delta->spi->master); spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true; sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
reinit_completion(&sigma_delta->completion); reinit_completion(&sigma_delta->completion);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
...@@ -298,9 +301,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ...@@ -298,9 +301,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
ret = wait_for_completion_interruptible_timeout( ret = wait_for_completion_interruptible_timeout(
&sigma_delta->completion, HZ); &sigma_delta->completion, HZ);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
if (ret == 0) if (ret == 0)
ret = -EIO; ret = -EIO;
if (ret < 0) if (ret < 0)
...@@ -321,7 +321,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ...@@ -321,7 +321,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
sigma_delta->irq_dis = true; sigma_delta->irq_dis = true;
} }
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
if (ret) if (ret)
...@@ -358,6 +361,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) ...@@ -358,6 +361,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
spi_bus_lock(sigma_delta->spi->master); spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true; sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
if (ret) if (ret)
goto err_unlock; goto err_unlock;
...@@ -386,6 +391,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) ...@@ -386,6 +391,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
sigma_delta->irq_dis = true; sigma_delta->irq_dis = true;
} }
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false; sigma_delta->bus_locked = false;
......
...@@ -302,10 +302,8 @@ static int ingenic_adc_probe(struct platform_device *pdev) ...@@ -302,10 +302,8 @@ static int ingenic_adc_probe(struct platform_device *pdev)
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(dev, mem_base); adc->base = devm_ioremap_resource(dev, mem_base);
if (IS_ERR(adc->base)) { if (IS_ERR(adc->base))
dev_err(dev, "Unable to ioremap mmio resource\n");
return PTR_ERR(adc->base); return PTR_ERR(adc->base);
}
adc->clk = devm_clk_get(dev, "adc"); adc->clk = devm_clk_get(dev, "adc");
if (IS_ERR(adc->clk)) { if (IS_ERR(adc->clk)) {
......
...@@ -7,20 +7,15 @@ ...@@ -7,20 +7,15 @@
* Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de> * Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
*/ */
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/of.h> #include <linux/err.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/* /*
* LPC32XX registers definitions * LPC32XX registers definitions
...@@ -52,6 +47,7 @@ struct lpc32xx_adc_state { ...@@ -52,6 +47,7 @@ struct lpc32xx_adc_state {
void __iomem *adc_base; void __iomem *adc_base;
struct clk *clk; struct clk *clk;
struct completion completion; struct completion completion;
struct regulator *vref;
u32 value; u32 value;
}; };
...@@ -64,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, ...@@ -64,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
{ {
struct lpc32xx_adc_state *st = iio_priv(indio_dev); struct lpc32xx_adc_state *st = iio_priv(indio_dev);
int ret; int ret;
if (mask == IIO_CHAN_INFO_RAW) {
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
ret = clk_prepare_enable(st->clk); ret = clk_prepare_enable(st->clk);
if (ret) { if (ret) {
...@@ -84,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, ...@@ -84,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT; return IIO_VAL_INT;
}
return -EINVAL; case IIO_CHAN_INFO_SCALE:
*val = regulator_get_voltage(st->vref) / 1000;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
} }
static const struct iio_info lpc32xx_adc_iio_info = { static const struct iio_info lpc32xx_adc_iio_info = {
.read_raw = &lpc32xx_read_raw, .read_raw = &lpc32xx_read_raw,
}; };
#define LPC32XX_ADC_CHANNEL(_index) { \ #define LPC32XX_ADC_CHANNEL_BASE(_index) \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.channel = _index, \ .channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.address = LPC32XXAD_IN * _index, \ .address = LPC32XXAD_IN * _index, \
.scan_index = _index, \ .scan_index = _index,
#define LPC32XX_ADC_CHANNEL(_index) { \
LPC32XX_ADC_CHANNEL_BASE(_index) \
}
#define LPC32XX_ADC_SCALE_CHANNEL(_index) { \
LPC32XX_ADC_CHANNEL_BASE(_index) \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
} }
static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
...@@ -108,6 +120,12 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { ...@@ -108,6 +120,12 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
LPC32XX_ADC_CHANNEL(2), LPC32XX_ADC_CHANNEL(2),
}; };
static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = {
LPC32XX_ADC_SCALE_CHANNEL(0),
LPC32XX_ADC_SCALE_CHANNEL(1),
LPC32XX_ADC_SCALE_CHANNEL(2),
};
static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
{ {
struct lpc32xx_adc_state *st = dev_id; struct lpc32xx_adc_state *st = dev_id;
...@@ -166,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) ...@@ -166,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
return retval; return retval;
} }
st->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(st->vref)) {
iodev->channels = lpc32xx_adc_iio_channels;
dev_info(&pdev->dev,
"Missing vref regulator: No scaling available\n");
} else {
iodev->channels = lpc32xx_adc_iio_scale_channels;
}
platform_set_drvdata(pdev, iodev); platform_set_drvdata(pdev, iodev);
init_completion(&st->completion); init_completion(&st->completion);
...@@ -174,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) ...@@ -174,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
iodev->dev.parent = &pdev->dev; iodev->dev.parent = &pdev->dev;
iodev->info = &lpc32xx_adc_iio_info; iodev->info = &lpc32xx_adc_iio_info;
iodev->modes = INDIO_DIRECT_MODE; iodev->modes = INDIO_DIRECT_MODE;
iodev->channels = lpc32xx_adc_iio_channels;
iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
retval = devm_iio_device_register(&pdev->dev, iodev); retval = devm_iio_device_register(&pdev->dev, iodev);
......
...@@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { ...@@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = {
.name = "meson-axg-saradc", .name = "meson-axg-saradc",
}; };
static const struct meson_sar_adc_data meson_sar_adc_g12a_data = {
.param = &meson_sar_adc_gxl_param,
.name = "meson-g12a-saradc",
};
static const struct of_device_id meson_sar_adc_of_match[] = { static const struct of_device_id meson_sar_adc_of_match[] = {
{ {
.compatible = "amlogic,meson8-saradc", .compatible = "amlogic,meson8-saradc",
...@@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { ...@@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
}, { }, {
.compatible = "amlogic,meson-axg-saradc", .compatible = "amlogic,meson-axg-saradc",
.data = &meson_sar_adc_axg_data, .data = &meson_sar_adc_axg_data,
}, {
.compatible = "amlogic,meson-g12a-saradc",
.data = &meson_sar_adc_g12a_data,
}, },
{}, {},
}; };
......
...@@ -465,6 +465,8 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio) ...@@ -465,6 +465,8 @@ static int mxs_lradc_adc_trigger_init(struct iio_dev *iio)
trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name, trig = devm_iio_trigger_alloc(&iio->dev, "%s-dev%i", iio->name,
iio->id); iio->id);
if (!trig)
return -ENOMEM;
trig->dev.parent = adc->dev; trig->dev.parent = adc->dev;
iio_trigger_set_drvdata(trig, iio); iio_trigger_set_drvdata(trig, iio);
......
This diff is collapsed.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -90,6 +92,36 @@ struct dfsdm_priv { ...@@ -90,6 +92,36 @@ struct dfsdm_priv {
struct clk *aclk; /* audio clock */ struct clk *aclk; /* audio clock */
}; };
static inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm)
{
return container_of(dfsdm, struct dfsdm_priv, dfsdm);
}
static int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm)
{
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
int ret;
ret = clk_prepare_enable(priv->clk);
if (ret || !priv->aclk)
return ret;
ret = clk_prepare_enable(priv->aclk);
if (ret)
clk_disable_unprepare(priv->clk);
return ret;
}
static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm)
{
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
clk_disable_unprepare(priv->clk);
}
/** /**
* stm32_dfsdm_start_dfsdm - start global dfsdm interface. * stm32_dfsdm_start_dfsdm - start global dfsdm interface.
* *
...@@ -98,24 +130,17 @@ struct dfsdm_priv { ...@@ -98,24 +130,17 @@ struct dfsdm_priv {
*/ */
int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
{ {
struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
struct device *dev = &priv->pdev->dev; struct device *dev = &priv->pdev->dev;
unsigned int clk_div = priv->spi_clk_out_div, clk_src; unsigned int clk_div = priv->spi_clk_out_div, clk_src;
int ret; int ret;
if (atomic_inc_return(&priv->n_active_ch) == 1) { if (atomic_inc_return(&priv->n_active_ch) == 1) {
ret = clk_prepare_enable(priv->clk); ret = pm_runtime_get_sync(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to start clock\n"); pm_runtime_put_noidle(dev);
goto error_ret; goto error_ret;
} }
if (priv->aclk) {
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(dev, "Failed to start audio clock\n");
goto disable_clk;
}
}
/* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */
clk_src = priv->aclk ? 1 : 0; clk_src = priv->aclk ? 1 : 0;
...@@ -123,21 +148,21 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) ...@@ -123,21 +148,21 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
DFSDM_CHCFGR1_CKOUTSRC_MASK, DFSDM_CHCFGR1_CKOUTSRC_MASK,
DFSDM_CHCFGR1_CKOUTSRC(clk_src)); DFSDM_CHCFGR1_CKOUTSRC(clk_src));
if (ret < 0) if (ret < 0)
goto disable_aclk; goto pm_put;
/* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_CKOUTDIV_MASK, DFSDM_CHCFGR1_CKOUTDIV_MASK,
DFSDM_CHCFGR1_CKOUTDIV(clk_div)); DFSDM_CHCFGR1_CKOUTDIV(clk_div));
if (ret < 0) if (ret < 0)
goto disable_aclk; goto pm_put;
/* Global enable of DFSDM interface */ /* Global enable of DFSDM interface */
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_DFSDMEN_MASK, DFSDM_CHCFGR1_DFSDMEN_MASK,
DFSDM_CHCFGR1_DFSDMEN(1)); DFSDM_CHCFGR1_DFSDMEN(1));
if (ret < 0) if (ret < 0)
goto disable_aclk; goto pm_put;
} }
dev_dbg(dev, "%s: n_active_ch %d\n", __func__, dev_dbg(dev, "%s: n_active_ch %d\n", __func__,
...@@ -145,11 +170,8 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) ...@@ -145,11 +170,8 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
return 0; return 0;
disable_aclk: pm_put:
clk_disable_unprepare(priv->aclk); pm_runtime_put_sync(dev);
disable_clk:
clk_disable_unprepare(priv->clk);
error_ret: error_ret:
atomic_dec(&priv->n_active_ch); atomic_dec(&priv->n_active_ch);
...@@ -165,7 +187,7 @@ EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); ...@@ -165,7 +187,7 @@ EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm);
*/ */
int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm)
{ {
struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
int ret; int ret;
if (atomic_dec_and_test(&priv->n_active_ch)) { if (atomic_dec_and_test(&priv->n_active_ch)) {
...@@ -183,9 +205,7 @@ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) ...@@ -183,9 +205,7 @@ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm)
if (ret < 0) if (ret < 0)
return ret; return ret;
clk_disable_unprepare(priv->clk); pm_runtime_put_sync(&priv->pdev->dev);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
} }
dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__,
atomic_read(&priv->n_active_ch)); atomic_read(&priv->n_active_ch));
...@@ -199,7 +219,7 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, ...@@ -199,7 +219,7 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
{ {
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct resource *res; struct resource *res;
unsigned long clk_freq; unsigned long clk_freq, divider;
unsigned int spi_freq, rem; unsigned int spi_freq, rem;
int ret; int ret;
...@@ -243,13 +263,20 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, ...@@ -243,13 +263,20 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
return 0; return 0;
} }
priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; divider = div_u64_rem(clk_freq, spi_freq, &rem);
if (!priv->spi_clk_out_div) { /* Round up divider when ckout isn't precise, not to exceed spi_freq */
/* spi_clk_out_div == 0 means ckout is OFF */ if (rem)
divider++;
/* programmable divider is in range of [2:256] */
if (divider < 2 || divider > 256) {
dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); dev_err(&pdev->dev, "spi-max-frequency not achievable\n");
return -EINVAL; return -EINVAL;
} }
priv->dfsdm.spi_master_freq = spi_freq;
/* SPI clock output divider is: divider = CKOUTDIV + 1 */
priv->spi_clk_out_div = divider - 1;
priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1);
if (rem) { if (rem) {
dev_warn(&pdev->dev, "SPI clock not accurate\n"); dev_warn(&pdev->dev, "SPI clock not accurate\n");
...@@ -318,14 +345,111 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) ...@@ -318,14 +345,111 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dfsdm); platform_set_drvdata(pdev, dfsdm);
return devm_of_platform_populate(&pdev->dev); ret = stm32_dfsdm_clk_prepare_enable(dfsdm);
if (ret) {
dev_err(&pdev->dev, "Failed to start clock\n");
return ret;
}
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
if (ret)
goto pm_put;
pm_runtime_put(&pdev->dev);
return 0;
pm_put:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
stm32_dfsdm_clk_disable_unprepare(dfsdm);
return ret;
}
static int stm32_dfsdm_core_remove(struct platform_device *pdev)
{
struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
of_platform_depopulate(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
stm32_dfsdm_clk_disable_unprepare(dfsdm);
return 0;
}
static int __maybe_unused stm32_dfsdm_core_suspend(struct device *dev)
{
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
int ret;
ret = pm_runtime_force_suspend(dev);
if (ret)
return ret;
/* Balance devm_regmap_init_mmio_clk() clk_prepare() */
clk_unprepare(priv->clk);
return pinctrl_pm_select_sleep_state(dev);
} }
static int __maybe_unused stm32_dfsdm_core_resume(struct device *dev)
{
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret)
return ret;
ret = clk_prepare(priv->clk);
if (ret)
return ret;
return pm_runtime_force_resume(dev);
}
static int __maybe_unused stm32_dfsdm_core_runtime_suspend(struct device *dev)
{
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
stm32_dfsdm_clk_disable_unprepare(dfsdm);
return 0;
}
static int __maybe_unused stm32_dfsdm_core_runtime_resume(struct device *dev)
{
struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev);
return stm32_dfsdm_clk_prepare_enable(dfsdm);
}
static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend,
stm32_dfsdm_core_resume)
SET_RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend,
stm32_dfsdm_core_runtime_resume,
NULL)
};
static struct platform_driver stm32_dfsdm_driver = { static struct platform_driver stm32_dfsdm_driver = {
.probe = stm32_dfsdm_probe, .probe = stm32_dfsdm_probe,
.remove = stm32_dfsdm_core_remove,
.driver = { .driver = {
.name = "stm32-dfsdm", .name = "stm32-dfsdm",
.of_match_table = stm32_dfsdm_of_match, .of_match_table = stm32_dfsdm_of_match,
.pm = &stm32_dfsdm_core_pm_ops,
}, },
}; };
......
...@@ -184,9 +184,6 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) ...@@ -184,9 +184,6 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
struct stmpe_adc *info = (struct stmpe_adc *)dev_id; struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
u16 data; u16 data;
if (info->channel > STMPE_TEMP_CHANNEL)
return IRQ_NONE;
if (info->channel <= STMPE_ADC_LAST_NR) { if (info->channel <= STMPE_ADC_LAST_NR) {
int int_sta; int int_sta;
...@@ -205,6 +202,8 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) ...@@ -205,6 +202,8 @@ static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
/* Read value */ /* Read value */
stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2, stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2,
(u8 *) &data); (u8 *) &data);
} else {
return IRQ_NONE;
} }
info->value = (u32) be16_to_cpu(data); info->value = (u32) be16_to_cpu(data);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -36,12 +37,15 @@ ...@@ -36,12 +37,15 @@
*/ */
#define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000 #define TI_ADS7950_VA_MV_ACPI_DEFAULT 5000
#define TI_ADS7950_CR_GPIO BIT(14)
#define TI_ADS7950_CR_MANUAL BIT(12) #define TI_ADS7950_CR_MANUAL BIT(12)
#define TI_ADS7950_CR_WRITE BIT(11) #define TI_ADS7950_CR_WRITE BIT(11)
#define TI_ADS7950_CR_CHAN(ch) ((ch) << 7) #define TI_ADS7950_CR_CHAN(ch) ((ch) << 7)
#define TI_ADS7950_CR_RANGE_5V BIT(6) #define TI_ADS7950_CR_RANGE_5V BIT(6)
#define TI_ADS7950_CR_GPIO_DATA BIT(4)
#define TI_ADS7950_MAX_CHAN 16 #define TI_ADS7950_MAX_CHAN 16
#define TI_ADS7950_NUM_GPIOS 4
#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16)) #define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
...@@ -49,6 +53,16 @@ ...@@ -49,6 +53,16 @@
#define TI_ADS7950_EXTRACT(val, dec, bits) \ #define TI_ADS7950_EXTRACT(val, dec, bits) \
(((val) >> (dec)) & ((1 << (bits)) - 1)) (((val) >> (dec)) & ((1 << (bits)) - 1))
#define TI_ADS7950_MAN_CMD(cmd) (TI_ADS7950_CR_MANUAL | (cmd))
#define TI_ADS7950_GPIO_CMD(cmd) (TI_ADS7950_CR_GPIO | (cmd))
/* Manual mode configuration */
#define TI_ADS7950_MAN_CMD_SETTINGS(st) \
(TI_ADS7950_MAN_CMD(TI_ADS7950_CR_WRITE | st->cmd_settings_bitmask))
/* GPIO mode configuration */
#define TI_ADS7950_GPIO_CMD_SETTINGS(st) \
(TI_ADS7950_GPIO_CMD(st->gpio_cmd_settings_bitmask))
struct ti_ads7950_state { struct ti_ads7950_state {
struct spi_device *spi; struct spi_device *spi;
struct spi_transfer ring_xfer; struct spi_transfer ring_xfer;
...@@ -56,10 +70,36 @@ struct ti_ads7950_state { ...@@ -56,10 +70,36 @@ struct ti_ads7950_state {
struct spi_message ring_msg; struct spi_message ring_msg;
struct spi_message scan_single_msg; struct spi_message scan_single_msg;
/* Lock to protect the spi xfer buffers */
struct mutex slock;
struct gpio_chip chip;
struct regulator *reg; struct regulator *reg;
unsigned int vref_mv; unsigned int vref_mv;
unsigned int settings; /*
* Bitmask of lower 7 bits used for configuration
* These bits only can be written when TI_ADS7950_CR_WRITE
* is set, otherwise it retains its original state.
* [0-3] GPIO signal
* [4] Set following frame to return GPIO signal values
* [5] Powers down device
* [6] Sets Vref range1(2.5v) or range2(5v)
*
* Bits present on Manual/Auto1/Auto2 commands
*/
unsigned int cmd_settings_bitmask;
/*
* Bitmask of GPIO command
* [0-3] GPIO direction
* [4-6] Different GPIO alarm mode configurations
* [7] GPIO 2 as device range input
* [8] GPIO 3 as device power down input
* [9] Reset all registers
* [10-11] N/A
*/
unsigned int gpio_cmd_settings_bitmask;
/* /*
* DMA (thus cache coherency maintenance) requires the * DMA (thus cache coherency maintenance) requires the
...@@ -248,7 +288,7 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev, ...@@ -248,7 +288,7 @@ static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev,
len = 0; len = 0;
for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) {
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings; cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(i));
st->tx_buf[len++] = cmd; st->tx_buf[len++] = cmd;
} }
...@@ -268,6 +308,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) ...@@ -268,6 +308,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
struct ti_ads7950_state *st = iio_priv(indio_dev); struct ti_ads7950_state *st = iio_priv(indio_dev);
int ret; int ret;
mutex_lock(&st->slock);
ret = spi_sync(st->spi, &st->ring_msg); ret = spi_sync(st->spi, &st->ring_msg);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -276,6 +317,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) ...@@ -276,6 +317,7 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
iio_get_time_ns(indio_dev)); iio_get_time_ns(indio_dev));
out: out:
mutex_unlock(&st->slock);
iio_trigger_notify_done(indio_dev->trig); iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -286,9 +328,8 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) ...@@ -286,9 +328,8 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
struct ti_ads7950_state *st = iio_priv(indio_dev); struct ti_ads7950_state *st = iio_priv(indio_dev);
int ret, cmd; int ret, cmd;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->slock);
cmd = TI_ADS7950_MAN_CMD(TI_ADS7950_CR_CHAN(ch));
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
st->single_tx = cmd; st->single_tx = cmd;
ret = spi_sync(st->spi, &st->scan_single_msg); ret = spi_sync(st->spi, &st->scan_single_msg);
...@@ -298,7 +339,7 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch) ...@@ -298,7 +339,7 @@ static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
ret = st->single_rx; ret = st->single_rx;
out: out:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->slock);
return ret; return ret;
} }
...@@ -317,7 +358,7 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st) ...@@ -317,7 +358,7 @@ static int ti_ads7950_get_range(struct ti_ads7950_state *st)
vref /= 1000; vref /= 1000;
} }
if (st->settings & TI_ADS7950_CR_RANGE_5V) if (st->cmd_settings_bitmask & TI_ADS7950_CR_RANGE_5V)
vref *= 2; vref *= 2;
return vref; return vref;
...@@ -362,6 +403,132 @@ static const struct iio_info ti_ads7950_info = { ...@@ -362,6 +403,132 @@ static const struct iio_info ti_ads7950_info = {
.update_scan_mode = ti_ads7950_update_scan_mode, .update_scan_mode = ti_ads7950_update_scan_mode,
}; };
static void ti_ads7950_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
mutex_lock(&st->slock);
if (value)
st->cmd_settings_bitmask |= BIT(offset);
else
st->cmd_settings_bitmask &= ~BIT(offset);
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
spi_sync(st->spi, &st->scan_single_msg);
mutex_unlock(&st->slock);
}
static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
int ret;
mutex_lock(&st->slock);
/* If set as output, return the output */
if (st->gpio_cmd_settings_bitmask & BIT(offset)) {
ret = st->cmd_settings_bitmask & BIT(offset);
goto out;
}
/* GPIO data bit sets SDO bits 12-15 to GPIO input */
st->cmd_settings_bitmask |= TI_ADS7950_CR_GPIO_DATA;
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
goto out;
ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0;
/* Revert back to original settings */
st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA;
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
goto out;
out:
mutex_unlock(&st->slock);
return ret;
}
static int ti_ads7950_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
/* Bitmask is inverted from GPIO framework 0=input/1=output */
return !(st->gpio_cmd_settings_bitmask & BIT(offset));
}
static int _ti_ads7950_set_direction(struct gpio_chip *chip, int offset,
int input)
{
struct ti_ads7950_state *st = gpiochip_get_data(chip);
int ret = 0;
mutex_lock(&st->slock);
/* Only change direction if needed */
if (input && (st->gpio_cmd_settings_bitmask & BIT(offset)))
st->gpio_cmd_settings_bitmask &= ~BIT(offset);
else if (!input && !(st->gpio_cmd_settings_bitmask & BIT(offset)))
st->gpio_cmd_settings_bitmask |= BIT(offset);
else
goto out;
st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
out:
mutex_unlock(&st->slock);
return ret;
}
static int ti_ads7950_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
return _ti_ads7950_set_direction(chip, offset, 1);
}
static int ti_ads7950_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
ti_ads7950_set(chip, offset, value);
return _ti_ads7950_set_direction(chip, offset, 0);
}
static int ti_ads7950_init_hw(struct ti_ads7950_state *st)
{
int ret = 0;
mutex_lock(&st->slock);
/* Settings for Manual/Auto1/Auto2 commands */
/* Default to 5v ref */
st->cmd_settings_bitmask = TI_ADS7950_CR_RANGE_5V;
st->single_tx = TI_ADS7950_MAN_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
goto out;
/* Settings for GPIO command */
st->gpio_cmd_settings_bitmask = 0x0;
st->single_tx = TI_ADS7950_GPIO_CMD_SETTINGS(st);
ret = spi_sync(st->spi, &st->scan_single_msg);
out:
mutex_unlock(&st->slock);
return ret;
}
static int ti_ads7950_probe(struct spi_device *spi) static int ti_ads7950_probe(struct spi_device *spi)
{ {
struct ti_ads7950_state *st; struct ti_ads7950_state *st;
...@@ -386,7 +553,6 @@ static int ti_ads7950_probe(struct spi_device *spi) ...@@ -386,7 +553,6 @@ static int ti_ads7950_probe(struct spi_device *spi)
spi_set_drvdata(spi, indio_dev); spi_set_drvdata(spi, indio_dev);
st->spi = spi; st->spi = spi;
st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V;
info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data]; info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data];
...@@ -432,16 +598,19 @@ static int ti_ads7950_probe(struct spi_device *spi) ...@@ -432,16 +598,19 @@ static int ti_ads7950_probe(struct spi_device *spi)
if (ACPI_COMPANION(&spi->dev)) if (ACPI_COMPANION(&spi->dev))
st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT; st->vref_mv = TI_ADS7950_VA_MV_ACPI_DEFAULT;
mutex_init(&st->slock);
st->reg = devm_regulator_get(&spi->dev, "vref"); st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) { if (IS_ERR(st->reg)) {
dev_err(&spi->dev, "Failed get get regulator \"vref\"\n"); dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
return PTR_ERR(st->reg); ret = PTR_ERR(st->reg);
goto error_destroy_mutex;
} }
ret = regulator_enable(st->reg); ret = regulator_enable(st->reg);
if (ret) { if (ret) {
dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
return ret; goto error_destroy_mutex;
} }
ret = iio_triggered_buffer_setup(indio_dev, NULL, ret = iio_triggered_buffer_setup(indio_dev, NULL,
...@@ -451,18 +620,46 @@ static int ti_ads7950_probe(struct spi_device *spi) ...@@ -451,18 +620,46 @@ static int ti_ads7950_probe(struct spi_device *spi)
goto error_disable_reg; goto error_disable_reg;
} }
ret = ti_ads7950_init_hw(st);
if (ret) {
dev_err(&spi->dev, "Failed to init adc chip\n");
goto error_cleanup_ring;
}
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
if (ret) { if (ret) {
dev_err(&spi->dev, "Failed to register iio device\n"); dev_err(&spi->dev, "Failed to register iio device\n");
goto error_cleanup_ring; goto error_cleanup_ring;
} }
/* Add GPIO chip */
st->chip.label = dev_name(&st->spi->dev);
st->chip.parent = &st->spi->dev;
st->chip.owner = THIS_MODULE;
st->chip.base = -1;
st->chip.ngpio = TI_ADS7950_NUM_GPIOS;
st->chip.get_direction = ti_ads7950_get_direction;
st->chip.direction_input = ti_ads7950_direction_input;
st->chip.direction_output = ti_ads7950_direction_output;
st->chip.get = ti_ads7950_get;
st->chip.set = ti_ads7950_set;
ret = gpiochip_add_data(&st->chip, st);
if (ret) {
dev_err(&spi->dev, "Failed to init GPIOs\n");
goto error_iio_device;
}
return 0; return 0;
error_iio_device:
iio_device_unregister(indio_dev);
error_cleanup_ring: error_cleanup_ring:
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg: error_disable_reg:
regulator_disable(st->reg); regulator_disable(st->reg);
error_destroy_mutex:
mutex_destroy(&st->slock);
return ret; return ret;
} }
...@@ -472,9 +669,11 @@ static int ti_ads7950_remove(struct spi_device *spi) ...@@ -472,9 +669,11 @@ static int ti_ads7950_remove(struct spi_device *spi)
struct iio_dev *indio_dev = spi_get_drvdata(spi); struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ti_ads7950_state *st = iio_priv(indio_dev); struct ti_ads7950_state *st = iio_priv(indio_dev);
gpiochip_remove(&st->chip);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg); regulator_disable(st->reg);
mutex_destroy(&st->slock);
return 0; return 0;
} }
......
...@@ -523,6 +523,6 @@ static struct spi_driver ads8688_driver = { ...@@ -523,6 +523,6 @@ static struct spi_driver ads8688_driver = {
}; };
module_spi_driver(ads8688_driver); module_spi_driver(ads8688_driver);
MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>");
MODULE_DESCRIPTION("Texas Instruments ADS8688 driver"); MODULE_DESCRIPTION("Texas Instruments ADS8688 driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -36,7 +36,8 @@ static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data) ...@@ -36,7 +36,8 @@ static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data)
static void iio_buffer_cb_release(struct iio_buffer *buffer) static void iio_buffer_cb_release(struct iio_buffer *buffer)
{ {
struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer); struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
kfree(cb_buff->buffer.scan_mask);
bitmap_free(cb_buff->buffer.scan_mask);
kfree(cb_buff); kfree(cb_buff);
} }
...@@ -74,9 +75,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, ...@@ -74,9 +75,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
} }
cb_buff->indio_dev = cb_buff->channels[0].indio_dev; cb_buff->indio_dev = cb_buff->channels[0].indio_dev;
cb_buff->buffer.scan_mask cb_buff->buffer.scan_mask = bitmap_zalloc(cb_buff->indio_dev->masklength,
= kcalloc(BITS_TO_LONGS(cb_buff->indio_dev->masklength), GFP_KERNEL);
sizeof(long), GFP_KERNEL);
if (cb_buff->buffer.scan_mask == NULL) { if (cb_buff->buffer.scan_mask == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_release_channels; goto error_release_channels;
...@@ -95,7 +95,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, ...@@ -95,7 +95,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
return cb_buff; return cb_buff;
error_free_scan_mask: error_free_scan_mask:
kfree(cb_buff->buffer.scan_mask); bitmap_free(cb_buff->buffer.scan_mask);
error_release_channels: error_release_channels:
iio_channel_release_all(cb_buff->channels); iio_channel_release_all(cb_buff->channels);
error_free_cb_buff: error_free_cb_buff:
......
...@@ -12,14 +12,14 @@ config ATLAS_PH_SENSOR ...@@ -12,14 +12,14 @@ config ATLAS_PH_SENSOR
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
select IRQ_WORK select IRQ_WORK
help help
Say Y here to build I2C interface support for the following Say Y here to build I2C interface support for the following
Atlas Scientific OEM SM sensors: Atlas Scientific OEM SM sensors:
* pH SM sensor * pH SM sensor
* EC SM sensor * EC SM sensor
* ORP SM sensor * ORP SM sensor
To compile this driver as module, choose M here: the To compile this driver as module, choose M here: the
module will be called atlas-ph-sensor. module will be called atlas-ph-sensor.
config BME680 config BME680
tristate "Bosch Sensortec BME680 sensor driver" tristate "Bosch Sensortec BME680 sensor driver"
...@@ -47,8 +47,8 @@ config BME680_SPI ...@@ -47,8 +47,8 @@ config BME680_SPI
config CCS811 config CCS811
tristate "AMS CCS811 VOC sensor" tristate "AMS CCS811 VOC sensor"
depends on I2C depends on I2C
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
help help
Say Y here to build I2C interface support for the AMS Say Y here to build I2C interface support for the AMS
CCS811 VOC (Volatile Organic Compounds) sensor CCS811 VOC (Volatile Organic Compounds) sensor
......
...@@ -321,7 +321,12 @@ static int pms7003_probe(struct serdev_device *serdev) ...@@ -321,7 +321,12 @@ static int pms7003_probe(struct serdev_device *serdev)
} }
static const struct of_device_id pms7003_of_match[] = { static const struct of_device_id pms7003_of_match[] = {
{ .compatible = "plantower,pms1003" },
{ .compatible = "plantower,pms3003" },
{ .compatible = "plantower,pms5003" },
{ .compatible = "plantower,pms6003" },
{ .compatible = "plantower,pms7003" }, { .compatible = "plantower,pms7003" },
{ .compatible = "plantower,pmsa003" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, pms7003_of_match); MODULE_DEVICE_TABLE(of, pms7003_of_match);
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors. * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors.
* *
* Copyright (C) 2016 Google, Inc * Copyright (C) 2016 Google, Inc
* *
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This driver uses the cros-ec interface to communicate with the Chrome OS * This driver uses the cros-ec interface to communicate with the Chrome OS
* EC about sensors data. Data access is presented through iio sysfs. * EC about sensors data. Data access is presented through iio sysfs.
*/ */
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/common/cros_ec_sensors_core.h>
...@@ -30,7 +21,6 @@ ...@@ -30,7 +21,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h>
#define CROS_EC_SENSORS_MAX_CHANNELS 4 #define CROS_EC_SENSORS_MAX_CHANNELS 4
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* cros_ec_sensors_core - Common function for Chrome OS EC sensor driver. * cros_ec_sensors_core - Common function for Chrome OS EC sensor driver.
* *
* Copyright (C) 2016 Google, Inc * Copyright (C) 2016 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/delay.h> #include <linux/delay.h>
...@@ -25,7 +17,6 @@ ...@@ -25,7 +17,6 @@
#include <linux/mfd/cros_ec_commands.h> #include <linux/mfd/cros_ec_commands.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
static char *cros_ec_loc[] = { static char *cros_ec_loc[] = {
...@@ -269,6 +260,17 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev, ...@@ -269,6 +260,17 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev,
return 0; return 0;
} }
/**
* cros_ec_sensors_read_lpc() - read acceleration data from EC shared memory.
* @indio_dev: pointer to IIO device.
* @scan_mask: bitmap of the sensor indices to scan.
* @data: location to store data.
*
* Note: this is the safe function for reading the EC data. It guarantees
* that the data sampled was not modified by the EC while being read.
*
* Return: 0 on success, -errno on failure.
*/
int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev,
unsigned long scan_mask, s16 *data) unsigned long scan_mask, s16 *data)
{ {
......
...@@ -3,4 +3,4 @@ ...@@ -3,4 +3,4 @@
# #
config IIO_MS_SENSORS_I2C config IIO_MS_SENSORS_I2C
tristate tristate
...@@ -81,7 +81,7 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf, ...@@ -81,7 +81,7 @@ int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
unsigned int len, int64_t timestamp) unsigned int len, int64_t timestamp)
{ {
__le32 time; __le32 time;
int64_t calculated_time; int64_t calculated_time = 0;
struct ssp_sensor_data *spd = iio_priv(indio_dev); struct ssp_sensor_data *spd = iio_priv(indio_dev);
if (indio_dev->scan_bytes == 0) if (indio_dev->scan_bytes == 0)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/mfd/stm32-lptimer.h> #include <linux/mfd/stm32-lptimer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
struct stm32_lptim_cnt { struct stm32_lptim_cnt {
...@@ -23,6 +24,7 @@ struct stm32_lptim_cnt { ...@@ -23,6 +24,7 @@ struct stm32_lptim_cnt {
u32 preset; u32 preset;
u32 polarity; u32 polarity;
u32 quadrature_mode; u32 quadrature_mode;
bool enabled;
}; };
static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv) static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)
...@@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, ...@@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
if (!enable) { if (!enable) {
clk_disable(priv->clk); clk_disable(priv->clk);
priv->enabled = false;
return 0; return 0;
} }
...@@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv, ...@@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
regmap_write(priv->regmap, STM32_LPTIM_CR, 0); regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
return ret; return ret;
} }
priv->enabled = true;
/* Start LP timer in continuous mode */ /* Start LP timer in continuous mode */
return regmap_update_bits(priv->regmap, STM32_LPTIM_CR, return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,
...@@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev) ...@@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev)
return devm_iio_device_register(&pdev->dev, indio_dev); return devm_iio_device_register(&pdev->dev, indio_dev);
} }
#ifdef CONFIG_PM_SLEEP
static int stm32_lptim_cnt_suspend(struct device *dev)
{
struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
int ret;
/* Only take care of enabled counter: don't disturb other MFD child */
if (priv->enabled) {
ret = stm32_lptim_setup(priv, 0);
if (ret)
return ret;
ret = stm32_lptim_set_enable_state(priv, 0);
if (ret)
return ret;
/* Force enable state for later resume */
priv->enabled = true;
}
return pinctrl_pm_select_sleep_state(dev);
}
static int stm32_lptim_cnt_resume(struct device *dev)
{
struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret)
return ret;
if (priv->enabled) {
priv->enabled = false;
ret = stm32_lptim_setup(priv, 1);
if (ret)
return ret;
ret = stm32_lptim_set_enable_state(priv, 1);
if (ret)
return ret;
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,
stm32_lptim_cnt_resume);
static const struct of_device_id stm32_lptim_cnt_of_match[] = { static const struct of_device_id stm32_lptim_cnt_of_match[] = {
{ .compatible = "st,stm32-lptimer-counter", }, { .compatible = "st,stm32-lptimer-counter", },
{}, {},
...@@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = { ...@@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = {
.driver = { .driver = {
.name = "stm32-lptimer-counter", .name = "stm32-lptimer-counter",
.of_match_table = stm32_lptim_cnt_of_match, .of_match_table = stm32_lptim_cnt_of_match,
.pm = &stm32_lptim_cnt_pm_ops,
}, },
}; };
module_platform_driver(stm32_lptim_cnt_driver); module_platform_driver(stm32_lptim_cnt_driver);
......
...@@ -112,6 +112,8 @@ struct ad5064_state { ...@@ -112,6 +112,8 @@ struct ad5064_state {
bool use_internal_vref; bool use_internal_vref;
ad5064_write_func write; ad5064_write_func write;
/* Lock used to maintain consistency between cached and dev state */
struct mutex lock;
/* /*
* DMA (thus cache coherency maintenance) requires the * DMA (thus cache coherency maintenance) requires the
...@@ -248,11 +250,11 @@ static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev, ...@@ -248,11 +250,11 @@ static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev,
struct ad5064_state *st = iio_priv(indio_dev); struct ad5064_state *st = iio_priv(indio_dev);
int ret; int ret;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
st->pwr_down_mode[chan->channel] = mode + 1; st->pwr_down_mode[chan->channel] = mode + 1;
ret = ad5064_sync_powerdown_mode(st, chan); ret = ad5064_sync_powerdown_mode(st, chan);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
return ret; return ret;
} }
...@@ -291,11 +293,11 @@ static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev, ...@@ -291,11 +293,11 @@ static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
if (ret) if (ret)
return ret; return ret;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
st->pwr_down[chan->channel] = pwr_down; st->pwr_down[chan->channel] = pwr_down;
ret = ad5064_sync_powerdown_mode(st, chan); ret = ad5064_sync_powerdown_mode(st, chan);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
return ret ? ret : len; return ret ? ret : len;
} }
...@@ -349,12 +351,12 @@ static int ad5064_write_raw(struct iio_dev *indio_dev, ...@@ -349,12 +351,12 @@ static int ad5064_write_raw(struct iio_dev *indio_dev,
if (val >= (1 << chan->scan_type.realbits) || val < 0) if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL; return -EINVAL;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N,
chan->address, val, chan->scan_type.shift); chan->address, val, chan->scan_type.shift);
if (ret == 0) if (ret == 0)
st->dac_cache[chan->channel] = val; st->dac_cache[chan->channel] = val;
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
...@@ -856,6 +858,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, ...@@ -856,6 +858,7 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type,
return -ENOMEM; return -ENOMEM;
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
mutex_init(&st->lock);
dev_set_drvdata(dev, indio_dev); dev_set_drvdata(dev, indio_dev);
st->chip_info = &ad5064_chip_info_tbl[type]; st->chip_info = &ad5064_chip_info_tbl[type];
......
...@@ -429,6 +429,6 @@ static struct i2c_driver dac5571_driver = { ...@@ -429,6 +429,6 @@ static struct i2c_driver dac5571_driver = {
}; };
module_i2c_driver(dac5571_driver); module_i2c_driver(dac5571_driver);
MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.dk>");
MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver"); MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
...@@ -872,22 +872,22 @@ static int ad9523_setup(struct iio_dev *indio_dev) ...@@ -872,22 +872,22 @@ static int ad9523_setup(struct iio_dev *indio_dev)
return ret; return ret;
ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER, ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER,
AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_diff_m1) | AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_div_m1) |
AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_diff_m2) | AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_div_m2) |
AD_IFE(pll2_vco_diff_m1, 0, AD_IFE(pll2_vco_div_m1, 0,
AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) | AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) |
AD_IFE(pll2_vco_diff_m2, 0, AD_IFE(pll2_vco_div_m2, 0,
AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN)); AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN));
if (ret < 0) if (ret < 0)
return ret; return ret;
if (pdata->pll2_vco_diff_m1) if (pdata->pll2_vco_div_m1)
st->vco_out_freq[AD9523_VCO1] = st->vco_out_freq[AD9523_VCO1] =
st->vco_freq / pdata->pll2_vco_diff_m1; st->vco_freq / pdata->pll2_vco_div_m1;
if (pdata->pll2_vco_diff_m2) if (pdata->pll2_vco_div_m2)
st->vco_out_freq[AD9523_VCO2] = st->vco_out_freq[AD9523_VCO2] =
st->vco_freq / pdata->pll2_vco_diff_m2; st->vco_freq / pdata->pll2_vco_div_m2;
st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq; st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq;
......
...@@ -102,6 +102,7 @@ struct bmg160_data { ...@@ -102,6 +102,7 @@ struct bmg160_data {
struct regmap *regmap; struct regmap *regmap;
struct iio_trigger *dready_trig; struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig; struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
struct mutex mutex; struct mutex mutex;
s16 buffer[8]; s16 buffer[8];
u32 dps_range; u32 dps_range;
...@@ -794,6 +795,20 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev, ...@@ -794,6 +795,20 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev,
return 0; return 0;
} }
static const struct iio_mount_matrix *
bmg160_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bmg160_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info bmg160_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmg160_get_mount_matrix),
{ }
};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000"); static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000");
static IIO_CONST_ATTR(in_anglvel_scale_available, static IIO_CONST_ATTR(in_anglvel_scale_available,
...@@ -831,6 +846,7 @@ static const struct iio_event_spec bmg160_event = { ...@@ -831,6 +846,7 @@ static const struct iio_event_spec bmg160_event = {
.storagebits = 16, \ .storagebits = 16, \
.endianness = IIO_LE, \ .endianness = IIO_LE, \
}, \ }, \
.ext_info = bmg160_ext_info, \
.event_spec = &bmg160_event, \ .event_spec = &bmg160_event, \
.num_event_specs = 1 \ .num_event_specs = 1 \
} }
...@@ -1075,6 +1091,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, ...@@ -1075,6 +1091,11 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->irq = irq; data->irq = irq;
data->regmap = regmap; data->regmap = regmap;
ret = iio_read_mount_matrix(dev, "mount-matrix",
&data->orientation);
if (ret)
return ret;
ret = bmg160_chip_init(data); ret = bmg160_chip_init(data);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -54,10 +54,19 @@ static const struct i2c_device_id bmg160_i2c_id[] = { ...@@ -54,10 +54,19 @@ static const struct i2c_device_id bmg160_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id); MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id);
static const struct of_device_id bmg160_of_match[] = {
{ .compatible = "bosch,bmg160" },
{ .compatible = "bosch,bmi055_gyro" },
{ }
};
MODULE_DEVICE_TABLE(of, bmg160_of_match);
static struct i2c_driver bmg160_i2c_driver = { static struct i2c_driver bmg160_i2c_driver = {
.driver = { .driver = {
.name = "bmg160_i2c", .name = "bmg160_i2c",
.acpi_match_table = ACPI_PTR(bmg160_acpi_match), .acpi_match_table = ACPI_PTR(bmg160_acpi_match),
.of_match_table = bmg160_of_match,
.pm = &bmg160_pm_ops, .pm = &bmg160_pm_ops,
}, },
.probe = bmg160_i2c_probe, .probe = bmg160_i2c_probe,
......
...@@ -242,6 +242,20 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev) ...@@ -242,6 +242,20 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev)
return ret; return ret;
} }
static const struct iio_mount_matrix *
itg3200_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct itg3200 *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info itg3200_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, itg3200_get_mount_matrix),
{ }
};
#define ITG3200_ST \ #define ITG3200_ST \
{ .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE } { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE }
...@@ -255,6 +269,7 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev) ...@@ -255,6 +269,7 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev)
.address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \ .address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
.scan_index = ITG3200_SCAN_GYRO_ ## _mod, \ .scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
.scan_type = ITG3200_ST, \ .scan_type = ITG3200_ST, \
.ext_info = itg3200_ext_info, \
} }
static const struct iio_chan_spec itg3200_channels[] = { static const struct iio_chan_spec itg3200_channels[] = {
...@@ -297,6 +312,11 @@ static int itg3200_probe(struct i2c_client *client, ...@@ -297,6 +312,11 @@ static int itg3200_probe(struct i2c_client *client,
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
&st->orientation);
if (ret)
return ret;
i2c_set_clientdata(client, indio_dev); i2c_set_clientdata(client, indio_dev);
st->i2c = client; st->i2c = client;
......
...@@ -1149,8 +1149,7 @@ int mpu3050_common_probe(struct device *dev, ...@@ -1149,8 +1149,7 @@ int mpu3050_common_probe(struct device *dev,
mpu3050->divisor = 99; mpu3050->divisor = 99;
/* Read the mounting matrix, if present */ /* Read the mounting matrix, if present */
ret = of_iio_read_mount_matrix(dev, "mount-matrix", ret = iio_read_mount_matrix(dev, "mount-matrix", &mpu3050->orientation);
&mpu3050->orientation);
if (ret) if (ret)
return ret; return ret;
......
...@@ -4,16 +4,16 @@ ...@@ -4,16 +4,16 @@
menu "Humidity sensors" menu "Humidity sensors"
config AM2315 config AM2315
tristate "Aosong AM2315 relative humidity and temperature sensor" tristate "Aosong AM2315 relative humidity and temperature sensor"
depends on I2C depends on I2C
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
help help
If you say yes here you get support for the Aosong AM2315 If you say yes here you get support for the Aosong AM2315
relative humidity and ambient temperature sensor. relative humidity and ambient temperature sensor.
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called am2315. be called am2315.
config DHT11 config DHT11
tristate "DHT11 (and compatible sensors) driver" tristate "DHT11 (and compatible sensors) driver"
...@@ -78,7 +78,7 @@ config HTS221_SPI ...@@ -78,7 +78,7 @@ config HTS221_SPI
config HTU21 config HTU21
tristate "Measurement Specialties HTU21 humidity & temperature sensor" tristate "Measurement Specialties HTU21 humidity & temperature sensor"
depends on I2C depends on I2C
select IIO_MS_SENSORS_I2C select IIO_MS_SENSORS_I2C
help help
If you say yes here you get support for the Measurement Specialties If you say yes here you get support for the Measurement Specialties
HTU21 humidity and temperature sensor. HTU21 humidity and temperature sensor.
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
# #
# When adding new entries keep the list in alphabetical order # When adding new entries keep the list in alphabetical order
adis16400-y := adis16400_core.o
adis16400-$(CONFIG_IIO_BUFFER) += adis16400_buffer.o
obj-$(CONFIG_ADIS16400) += adis16400.o obj-$(CONFIG_ADIS16400) += adis16400.o
obj-$(CONFIG_ADIS16480) += adis16480.o obj-$(CONFIG_ADIS16480) += adis16480.o
......
...@@ -31,8 +31,183 @@ ...@@ -31,8 +31,183 @@
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/imu/adis.h>
#define ADIS16400_STARTUP_DELAY 290 /* ms */
#define ADIS16400_MTEST_DELAY 90 /* ms */
#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */
#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */
#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */
#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */
#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */
#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */
#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */
#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */
#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */
#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */
#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */
#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */
#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */
#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */
#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */
#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */
#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */
#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */
/* Calibration parameters */
#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */
#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */
#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */
#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */
#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */
#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */
#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */
#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */
#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */
#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */
#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */
#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */
#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */
#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */
#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */
#define ADIS16400_DIAG_STAT 0x3C /* System status */
/* Alarm functions */
#define ADIS16400_GLOB_CMD 0x3E /* System command */
#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */
#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */
#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */
#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */
#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */
#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */
#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */
#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */
#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */
#define ADIS16400_ERROR_ACTIVE (1<<14)
#define ADIS16400_NEW_DATA (1<<14)
/* MSC_CTRL */
#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11)
#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10)
#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9)
#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8)
#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7)
#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6)
#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2)
#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
/* SMPL_PRD */
#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7)
#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F
/* DIAG_STAT */
#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15
#define ADIS16400_DIAG_STAT_YACCL_FAIL 14
#define ADIS16400_DIAG_STAT_XACCL_FAIL 13
#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12
#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11
#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10
#define ADIS16400_DIAG_STAT_ALARM2 9
#define ADIS16400_DIAG_STAT_ALARM1 8
#define ADIS16400_DIAG_STAT_FLASH_CHK 6
#define ADIS16400_DIAG_STAT_SELF_TEST 5
#define ADIS16400_DIAG_STAT_OVERFLOW 4
#define ADIS16400_DIAG_STAT_SPI_FAIL 3
#define ADIS16400_DIAG_STAT_FLASH_UPT 2
#define ADIS16400_DIAG_STAT_POWER_HIGH 1
#define ADIS16400_DIAG_STAT_POWER_LOW 0
/* GLOB_CMD */
#define ADIS16400_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4)
#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3)
#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2)
#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1)
#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0)
/* SLP_CNT */
#define ADIS16400_SLP_CNT_POWER_OFF (1<<8)
#define ADIS16334_RATE_DIV_SHIFT 8
#define ADIS16334_RATE_INT_CLK BIT(0)
#define ADIS16400_SPI_SLOW (u32)(300 * 1000)
#define ADIS16400_SPI_BURST (u32)(1000 * 1000)
#define ADIS16400_SPI_FAST (u32)(2000 * 1000)
#define ADIS16400_HAS_PROD_ID BIT(0)
#define ADIS16400_NO_BURST BIT(1)
#define ADIS16400_HAS_SLOW_MODE BIT(2)
#define ADIS16400_HAS_SERIAL_NUMBER BIT(3)
#define ADIS16400_BURST_DIAG_STAT BIT(4)
struct adis16400_state;
struct adis16400_chip_info {
const struct iio_chan_spec *channels;
const int num_channels;
const long flags;
unsigned int gyro_scale_micro;
unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
int (*set_freq)(struct adis16400_state *st, unsigned int freq);
int (*get_freq)(struct adis16400_state *st);
};
/**
* struct adis16400_state - device instance specific data
* @variant: chip variant info
* @filt_int: integer part of requested filter frequency
* @adis: adis device
**/
struct adis16400_state {
struct adis16400_chip_info *variant;
int filt_int;
struct adis adis;
unsigned long avail_scan_mask[2];
};
#include "adis16400.h" /* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
enum {
ADIS16400_SCAN_SUPPLY,
ADIS16400_SCAN_GYRO_X,
ADIS16400_SCAN_GYRO_Y,
ADIS16400_SCAN_GYRO_Z,
ADIS16400_SCAN_ACC_X,
ADIS16400_SCAN_ACC_Y,
ADIS16400_SCAN_ACC_Z,
ADIS16400_SCAN_MAGN_X,
ADIS16400_SCAN_MAGN_Y,
ADIS16400_SCAN_MAGN_Z,
ADIS16400_SCAN_BARO,
ADIS16350_SCAN_TEMP_X,
ADIS16350_SCAN_TEMP_Y,
ADIS16350_SCAN_TEMP_Z,
ADIS16300_SCAN_INCLI_X,
ADIS16300_SCAN_INCLI_Y,
ADIS16400_SCAN_ADC,
ADIS16400_SCAN_TIMESTAMP,
};
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -145,6 +320,11 @@ enum adis16400_chip_variant { ...@@ -145,6 +320,11 @@ enum adis16400_chip_variant {
ADIS16448, ADIS16448,
}; };
static struct adis_burst adis16400_burst = {
.en = true,
.reg_cmd = ADIS16400_GLOB_CMD,
};
static int adis16334_get_freq(struct adis16400_state *st) static int adis16334_get_freq(struct adis16400_state *st)
{ {
int ret; int ret;
...@@ -465,6 +645,51 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -465,6 +645,51 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
} }
} }
#if IS_ENABLED(CONFIG_IIO_BUFFER)
static irqreturn_t adis16400_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16400_state *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
u32 old_speed_hz = st->adis.spi->max_speed_hz;
void *buffer;
int ret;
if (!adis->buffer)
return -ENOMEM;
if (!(st->variant->flags & ADIS16400_NO_BURST) &&
st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
spi_setup(st->adis.spi);
}
ret = spi_sync(adis->spi, &adis->msg);
if (ret)
dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
if (!(st->variant->flags & ADIS16400_NO_BURST)) {
st->adis.spi->max_speed_hz = old_speed_hz;
spi_setup(st->adis.spi);
}
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
buffer = adis->buffer + sizeof(u16);
else
buffer = adis->buffer;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
#else
#define adis16400_trigger_handler NULL
#endif /* IS_ENABLED(CONFIG_IIO_BUFFER) */
#define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \ #define ADIS16400_VOLTAGE_CHAN(addr, bits, name, si, chn) { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
...@@ -835,7 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -835,7 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
static const struct iio_info adis16400_info = { static const struct iio_info adis16400_info = {
.read_raw = &adis16400_read_raw, .read_raw = &adis16400_read_raw,
.write_raw = &adis16400_write_raw, .write_raw = &adis16400_write_raw,
.update_scan_mode = adis16400_update_scan_mode, .update_scan_mode = adis_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access, .debugfs_reg_access = adis_debugfs_reg_access,
}; };
...@@ -926,6 +1151,9 @@ static int adis16400_probe(struct spi_device *spi) ...@@ -926,6 +1151,9 @@ static int adis16400_probe(struct spi_device *spi)
if (!(st->variant->flags & ADIS16400_NO_BURST)) { if (!(st->variant->flags & ADIS16400_NO_BURST)) {
adis16400_setup_chan_mask(st); adis16400_setup_chan_mask(st);
indio_dev->available_scan_masks = st->avail_scan_mask; indio_dev->available_scan_masks = st->avail_scan_mask;
st->adis.burst = &adis16400_burst;
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
st->adis.burst->extra_len = sizeof(u16);
} }
ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data); ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
......
/*
* adis16400.h support Analog Devices ADIS16400
* 3d 18g accelerometers,
* 3d gyroscopes,
* 3d 2.5gauss magnetometers via SPI
*
* Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de>
* Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org>
*
* Loosely based upon lis3l02dq.h
*
* 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.
*/
#ifndef SPI_ADIS16400_H_
#define SPI_ADIS16400_H_
#include <linux/iio/imu/adis.h>
#define ADIS16400_STARTUP_DELAY 290 /* ms */
#define ADIS16400_MTEST_DELAY 90 /* ms */
#define ADIS16400_FLASH_CNT 0x00 /* Flash memory write count */
#define ADIS16400_SUPPLY_OUT 0x02 /* Power supply measurement */
#define ADIS16400_XGYRO_OUT 0x04 /* X-axis gyroscope output */
#define ADIS16400_YGYRO_OUT 0x06 /* Y-axis gyroscope output */
#define ADIS16400_ZGYRO_OUT 0x08 /* Z-axis gyroscope output */
#define ADIS16400_XACCL_OUT 0x0A /* X-axis accelerometer output */
#define ADIS16400_YACCL_OUT 0x0C /* Y-axis accelerometer output */
#define ADIS16400_ZACCL_OUT 0x0E /* Z-axis accelerometer output */
#define ADIS16400_XMAGN_OUT 0x10 /* X-axis magnetometer measurement */
#define ADIS16400_YMAGN_OUT 0x12 /* Y-axis magnetometer measurement */
#define ADIS16400_ZMAGN_OUT 0x14 /* Z-axis magnetometer measurement */
#define ADIS16400_TEMP_OUT 0x16 /* Temperature output */
#define ADIS16400_AUX_ADC 0x18 /* Auxiliary ADC measurement */
#define ADIS16350_XTEMP_OUT 0x10 /* X-axis gyroscope temperature measurement */
#define ADIS16350_YTEMP_OUT 0x12 /* Y-axis gyroscope temperature measurement */
#define ADIS16350_ZTEMP_OUT 0x14 /* Z-axis gyroscope temperature measurement */
#define ADIS16300_PITCH_OUT 0x12 /* X axis inclinometer output measurement */
#define ADIS16300_ROLL_OUT 0x14 /* Y axis inclinometer output measurement */
#define ADIS16300_AUX_ADC 0x16 /* Auxiliary ADC measurement */
#define ADIS16448_BARO_OUT 0x16 /* Barometric pressure output */
#define ADIS16448_TEMP_OUT 0x18 /* Temperature output */
/* Calibration parameters */
#define ADIS16400_XGYRO_OFF 0x1A /* X-axis gyroscope bias offset factor */
#define ADIS16400_YGYRO_OFF 0x1C /* Y-axis gyroscope bias offset factor */
#define ADIS16400_ZGYRO_OFF 0x1E /* Z-axis gyroscope bias offset factor */
#define ADIS16400_XACCL_OFF 0x20 /* X-axis acceleration bias offset factor */
#define ADIS16400_YACCL_OFF 0x22 /* Y-axis acceleration bias offset factor */
#define ADIS16400_ZACCL_OFF 0x24 /* Z-axis acceleration bias offset factor */
#define ADIS16400_XMAGN_HIF 0x26 /* X-axis magnetometer, hard-iron factor */
#define ADIS16400_YMAGN_HIF 0x28 /* Y-axis magnetometer, hard-iron factor */
#define ADIS16400_ZMAGN_HIF 0x2A /* Z-axis magnetometer, hard-iron factor */
#define ADIS16400_XMAGN_SIF 0x2C /* X-axis magnetometer, soft-iron factor */
#define ADIS16400_YMAGN_SIF 0x2E /* Y-axis magnetometer, soft-iron factor */
#define ADIS16400_ZMAGN_SIF 0x30 /* Z-axis magnetometer, soft-iron factor */
#define ADIS16400_GPIO_CTRL 0x32 /* Auxiliary digital input/output control */
#define ADIS16400_MSC_CTRL 0x34 /* Miscellaneous control */
#define ADIS16400_SMPL_PRD 0x36 /* Internal sample period (rate) control */
#define ADIS16400_SENS_AVG 0x38 /* Dynamic range and digital filter control */
#define ADIS16400_SLP_CNT 0x3A /* Sleep mode control */
#define ADIS16400_DIAG_STAT 0x3C /* System status */
/* Alarm functions */
#define ADIS16400_GLOB_CMD 0x3E /* System command */
#define ADIS16400_ALM_MAG1 0x40 /* Alarm 1 amplitude threshold */
#define ADIS16400_ALM_MAG2 0x42 /* Alarm 2 amplitude threshold */
#define ADIS16400_ALM_SMPL1 0x44 /* Alarm 1 sample size */
#define ADIS16400_ALM_SMPL2 0x46 /* Alarm 2 sample size */
#define ADIS16400_ALM_CTRL 0x48 /* Alarm control */
#define ADIS16400_AUX_DAC 0x4A /* Auxiliary DAC data */
#define ADIS16334_LOT_ID1 0x52 /* Lot identification code 1 */
#define ADIS16334_LOT_ID2 0x54 /* Lot identification code 2 */
#define ADIS16400_PRODUCT_ID 0x56 /* Product identifier */
#define ADIS16334_SERIAL_NUMBER 0x58 /* Serial number, lot specific */
#define ADIS16400_ERROR_ACTIVE (1<<14)
#define ADIS16400_NEW_DATA (1<<14)
/* MSC_CTRL */
#define ADIS16400_MSC_CTRL_MEM_TEST (1<<11)
#define ADIS16400_MSC_CTRL_INT_SELF_TEST (1<<10)
#define ADIS16400_MSC_CTRL_NEG_SELF_TEST (1<<9)
#define ADIS16400_MSC_CTRL_POS_SELF_TEST (1<<8)
#define ADIS16400_MSC_CTRL_GYRO_BIAS (1<<7)
#define ADIS16400_MSC_CTRL_ACCL_ALIGN (1<<6)
#define ADIS16400_MSC_CTRL_DATA_RDY_EN (1<<2)
#define ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH (1<<1)
#define ADIS16400_MSC_CTRL_DATA_RDY_DIO2 (1<<0)
/* SMPL_PRD */
#define ADIS16400_SMPL_PRD_TIME_BASE (1<<7)
#define ADIS16400_SMPL_PRD_DIV_MASK 0x7F
/* DIAG_STAT */
#define ADIS16400_DIAG_STAT_ZACCL_FAIL 15
#define ADIS16400_DIAG_STAT_YACCL_FAIL 14
#define ADIS16400_DIAG_STAT_XACCL_FAIL 13
#define ADIS16400_DIAG_STAT_XGYRO_FAIL 12
#define ADIS16400_DIAG_STAT_YGYRO_FAIL 11
#define ADIS16400_DIAG_STAT_ZGYRO_FAIL 10
#define ADIS16400_DIAG_STAT_ALARM2 9
#define ADIS16400_DIAG_STAT_ALARM1 8
#define ADIS16400_DIAG_STAT_FLASH_CHK 6
#define ADIS16400_DIAG_STAT_SELF_TEST 5
#define ADIS16400_DIAG_STAT_OVERFLOW 4
#define ADIS16400_DIAG_STAT_SPI_FAIL 3
#define ADIS16400_DIAG_STAT_FLASH_UPT 2
#define ADIS16400_DIAG_STAT_POWER_HIGH 1
#define ADIS16400_DIAG_STAT_POWER_LOW 0
/* GLOB_CMD */
#define ADIS16400_GLOB_CMD_SW_RESET (1<<7)
#define ADIS16400_GLOB_CMD_P_AUTO_NULL (1<<4)
#define ADIS16400_GLOB_CMD_FLASH_UPD (1<<3)
#define ADIS16400_GLOB_CMD_DAC_LATCH (1<<2)
#define ADIS16400_GLOB_CMD_FAC_CALIB (1<<1)
#define ADIS16400_GLOB_CMD_AUTO_NULL (1<<0)
/* SLP_CNT */
#define ADIS16400_SLP_CNT_POWER_OFF (1<<8)
#define ADIS16334_RATE_DIV_SHIFT 8
#define ADIS16334_RATE_INT_CLK BIT(0)
#define ADIS16400_SPI_SLOW (u32)(300 * 1000)
#define ADIS16400_SPI_BURST (u32)(1000 * 1000)
#define ADIS16400_SPI_FAST (u32)(2000 * 1000)
#define ADIS16400_HAS_PROD_ID BIT(0)
#define ADIS16400_NO_BURST BIT(1)
#define ADIS16400_HAS_SLOW_MODE BIT(2)
#define ADIS16400_HAS_SERIAL_NUMBER BIT(3)
#define ADIS16400_BURST_DIAG_STAT BIT(4)
struct adis16400_state;
struct adis16400_chip_info {
const struct iio_chan_spec *channels;
const int num_channels;
const long flags;
unsigned int gyro_scale_micro;
unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
int (*set_freq)(struct adis16400_state *st, unsigned int freq);
int (*get_freq)(struct adis16400_state *st);
};
/**
* struct adis16400_state - device instance specific data
* @variant: chip variant info
* @filt_int: integer part of requested filter frequency
* @adis: adis device
**/
struct adis16400_state {
struct adis16400_chip_info *variant;
int filt_int;
struct adis adis;
unsigned long avail_scan_mask[2];
};
/* At the moment triggers are only used for ring buffer
* filling. This may change!
*/
enum {
ADIS16400_SCAN_SUPPLY,
ADIS16400_SCAN_GYRO_X,
ADIS16400_SCAN_GYRO_Y,
ADIS16400_SCAN_GYRO_Z,
ADIS16400_SCAN_ACC_X,
ADIS16400_SCAN_ACC_Y,
ADIS16400_SCAN_ACC_Z,
ADIS16400_SCAN_MAGN_X,
ADIS16400_SCAN_MAGN_Y,
ADIS16400_SCAN_MAGN_Z,
ADIS16400_SCAN_BARO,
ADIS16350_SCAN_TEMP_X,
ADIS16350_SCAN_TEMP_Y,
ADIS16350_SCAN_TEMP_Z,
ADIS16300_SCAN_INCLI_X,
ADIS16300_SCAN_INCLI_Y,
ADIS16400_SCAN_ADC,
ADIS16400_SCAN_TIMESTAMP,
};
#ifdef CONFIG_IIO_BUFFER
ssize_t adis16400_read_data_from_ring(struct device *dev,
struct device_attribute *attr,
char *buf);
int adis16400_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask);
irqreturn_t adis16400_trigger_handler(int irq, void *p);
#else /* CONFIG_IIO_BUFFER */
#define adis16400_update_scan_mode NULL
#define adis16400_trigger_handler NULL
#endif /* CONFIG_IIO_BUFFER */
#endif /* SPI_ADIS16400_H_ */
// SPDX-License-Identifier: GPL-2.0
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include "adis16400.h"
int adis16400_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct adis16400_state *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
unsigned int burst_length;
u8 *tx;
if (st->variant->flags & ADIS16400_NO_BURST)
return adis_update_scan_mode(indio_dev, scan_mask);
kfree(adis->xfer);
kfree(adis->buffer);
/* All but the timestamp channel */
burst_length = (indio_dev->num_channels - 1) * sizeof(u16);
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
burst_length += sizeof(u16);
adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
if (!adis->xfer)
return -ENOMEM;
adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
if (!adis->buffer)
return -ENOMEM;
tx = adis->buffer + burst_length;
tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
tx[1] = 0;
adis->xfer[0].tx_buf = tx;
adis->xfer[0].bits_per_word = 8;
adis->xfer[0].len = 2;
adis->xfer[1].rx_buf = adis->buffer;
adis->xfer[1].bits_per_word = 8;
adis->xfer[1].len = burst_length;
spi_message_init(&adis->msg);
spi_message_add_tail(&adis->xfer[0], &adis->msg);
spi_message_add_tail(&adis->xfer[1], &adis->msg);
return 0;
}
irqreturn_t adis16400_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16400_state *st = iio_priv(indio_dev);
struct adis *adis = &st->adis;
u32 old_speed_hz = st->adis.spi->max_speed_hz;
void *buffer;
int ret;
if (!adis->buffer)
return -ENOMEM;
if (!(st->variant->flags & ADIS16400_NO_BURST) &&
st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
spi_setup(st->adis.spi);
}
ret = spi_sync(adis->spi, &adis->msg);
if (ret)
dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
if (!(st->variant->flags & ADIS16400_NO_BURST)) {
st->adis.spi->max_speed_hz = old_speed_hz;
spi_setup(st->adis.spi);
}
if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
buffer = adis->buffer + sizeof(u16);
else
buffer = adis->buffer;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
This diff is collapsed.
...@@ -20,6 +20,43 @@ ...@@ -20,6 +20,43 @@
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#include <linux/iio/imu/adis.h> #include <linux/iio/imu/adis.h>
static int adis_update_scan_mode_burst(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct adis *adis = iio_device_get_drvdata(indio_dev);
unsigned int burst_length;
u8 *tx;
/* All but the timestamp channel */
burst_length = (indio_dev->num_channels - 1) * sizeof(u16);
burst_length += adis->burst->extra_len;
adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
if (!adis->xfer)
return -ENOMEM;
adis->buffer = kzalloc(burst_length + sizeof(u16), GFP_KERNEL);
if (!adis->buffer)
return -ENOMEM;
tx = adis->buffer + burst_length;
tx[0] = ADIS_READ_REG(adis->burst->reg_cmd);
tx[1] = 0;
adis->xfer[0].tx_buf = tx;
adis->xfer[0].bits_per_word = 8;
adis->xfer[0].len = 2;
adis->xfer[1].rx_buf = adis->buffer;
adis->xfer[1].bits_per_word = 8;
adis->xfer[1].len = burst_length;
spi_message_init(&adis->msg);
spi_message_add_tail(&adis->xfer[0], &adis->msg);
spi_message_add_tail(&adis->xfer[1], &adis->msg);
return 0;
}
int adis_update_scan_mode(struct iio_dev *indio_dev, int adis_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask) const unsigned long *scan_mask)
{ {
...@@ -32,6 +69,9 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, ...@@ -32,6 +69,9 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
kfree(adis->xfer); kfree(adis->xfer);
kfree(adis->buffer); kfree(adis->buffer);
if (adis->burst && adis->burst->en)
return adis_update_scan_mode_burst(indio_dev, scan_mask);
scan_count = indio_dev->scan_bytes / 2; scan_count = indio_dev->scan_bytes / 2;
adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL); adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL);
......
...@@ -796,12 +796,14 @@ static const struct iio_mount_matrix * ...@@ -796,12 +796,14 @@ static const struct iio_mount_matrix *
inv_get_mount_matrix(const struct iio_dev *indio_dev, inv_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan) const struct iio_chan_spec *chan)
{ {
return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation; struct inv_mpu6050_state *data = iio_priv(indio_dev);
return &data->orientation;
} }
static const struct iio_chan_spec_ext_info inv_ext_info[] = { static const struct iio_chan_spec_ext_info inv_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix), IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix),
{ }, { }
}; };
#define INV_MPU6050_CHAN(_type, _channel2, _index) \ #define INV_MPU6050_CHAN(_type, _channel2, _index) \
...@@ -1021,8 +1023,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, ...@@ -1021,8 +1023,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
pdata = dev_get_platdata(dev); pdata = dev_get_platdata(dev);
if (!pdata) { if (!pdata) {
result = of_iio_read_mount_matrix(dev, "mount-matrix", result = iio_read_mount_matrix(dev, "mount-matrix",
&st->orientation); &st->orientation);
if (result) { if (result) {
dev_err(dev, "Failed to retrieve mounting matrix %d\n", dev_err(dev, "Failed to retrieve mounting matrix %d\n",
result); result);
......
...@@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX ...@@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX
help help
Say yes here to build support for STMicroelectronics LSM6DSx imu Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc, lsm6dso ism330dlc, lsm6dso, lsm6dsox, asm330lhh
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx. will be called st_lsm6dsx.
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#define ST_LSM6DSM_DEV_NAME "lsm6dsm" #define ST_LSM6DSM_DEV_NAME "lsm6dsm"
#define ST_ISM330DLC_DEV_NAME "ism330dlc" #define ST_ISM330DLC_DEV_NAME "ism330dlc"
#define ST_LSM6DSO_DEV_NAME "lsm6dso" #define ST_LSM6DSO_DEV_NAME "lsm6dso"
#define ST_ASM330LHH_DEV_NAME "asm330lhh"
#define ST_LSM6DSOX_DEV_NAME "lsm6dsox"
enum st_lsm6dsx_hw_id { enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID, ST_LSM6DS3_ID,
...@@ -28,6 +30,8 @@ enum st_lsm6dsx_hw_id { ...@@ -28,6 +30,8 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSM_ID, ST_LSM6DSM_ID,
ST_ISM330DLC_ID, ST_ISM330DLC_ID,
ST_LSM6DSO_ID, ST_LSM6DSO_ID,
ST_ASM330LHH_ID,
ST_LSM6DSOX_ID,
ST_LSM6DSX_MAX_ID, ST_LSM6DSX_MAX_ID,
}; };
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
* value of the decimation factor and ODR set for each FIFO data set. * value of the decimation factor and ODR set for each FIFO data set.
* *
* LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and * LSM6DSO/LSM6DSOX/ASM330LHH: The FIFO buffer can be configured to store data
* accelerometer. Each sample is queued with a tag (1B) indicating data source * from gyroscope and accelerometer. Each sample is queued with a tag (1B)
* (gyroscope, accelerometer, hw timer). * indicating data source (gyroscope, accelerometer, hw timer).
* *
* FIFO supported modes: * FIFO supported modes:
* - BYPASS: FIFO disabled * - BYPASS: FIFO disabled
...@@ -506,7 +506,7 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, ...@@ -506,7 +506,7 @@ st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
} }
/** /**
* st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine * st_lsm6dsx_read_tagged_fifo() - LSM6DSO/LSM6DSOX/ASM330LHH read FIFO routine
* @hw: Pointer to instance of struct st_lsm6dsx_hw. * @hw: Pointer to instance of struct st_lsm6dsx_hw.
* *
* Read samples from the hw FIFO and push them to IIO buffers. * Read samples from the hw FIFO and push them to IIO buffers.
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB * - FIFO size: 4KB
* *
* - LSM6DSO * - LSM6DSO/LSM6DSOX/ASM330LHH
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
...@@ -287,6 +287,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { ...@@ -287,6 +287,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.max_fifo_size = 512, .max_fifo_size = 512,
.id = { .id = {
[0] = ST_LSM6DSO_ID, [0] = ST_LSM6DSO_ID,
[1] = ST_LSM6DSOX_ID,
}, },
.batch = { .batch = {
[ST_LSM6DSX_ID_ACC] = { [ST_LSM6DSX_ID_ACC] = {
...@@ -347,6 +348,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { ...@@ -347,6 +348,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.batch_en = BIT(3), .batch_en = BIT(3),
} }
}, },
{
.wai = 0x6b,
.max_fifo_size = 512,
.id = {
[0] = ST_ASM330LHH_ID,
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x09,
.mask = GENMASK(3, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x09,
.mask = GENMASK(7, 4),
},
},
.fifo_ops = {
.read_fifo = st_lsm6dsx_read_tagged_fifo,
.fifo_th = {
.addr = 0x07,
.mask = GENMASK(8, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(8, 0),
},
.th_wl = 1,
},
.ts_settings = {
.timer_en = {
.addr = 0x19,
.mask = BIT(5),
},
.decimator = {
.addr = 0x0a,
.mask = GENMASK(7, 6),
},
},
},
}; };
static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
......
...@@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { ...@@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,lsm6dso", .compatible = "st,lsm6dso",
.data = (void *)ST_LSM6DSO_ID, .data = (void *)ST_LSM6DSO_ID,
}, },
{
.compatible = "st,asm330lhh",
.data = (void *)ST_ASM330LHH_ID,
},
{
.compatible = "st,lsm6dsox",
.data = (void *)ST_LSM6DSOX_ID,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
...@@ -76,6 +84,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { ...@@ -76,6 +84,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
{ ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
{ ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
{}, {},
}; };
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
......
...@@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { ...@@ -65,6 +65,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,lsm6dso", .compatible = "st,lsm6dso",
.data = (void *)ST_LSM6DSO_ID, .data = (void *)ST_LSM6DSO_ID,
}, },
{
.compatible = "st,asm330lhh",
.data = (void *)ST_ASM330LHH_ID,
},
{
.compatible = "st,lsm6dsox",
.data = (void *)ST_LSM6DSOX_ID,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
...@@ -76,6 +84,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { ...@@ -76,6 +84,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
{ ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID }, { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
{ ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
{}, {},
}; };
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
......
This diff is collapsed.
This diff is collapsed.
...@@ -254,8 +254,11 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, ...@@ -254,8 +254,11 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
/* Get irq number */ /* Get irq number */
pf->irq = iio_trigger_get_irq(trig); pf->irq = iio_trigger_get_irq(trig);
if (pf->irq < 0) if (pf->irq < 0) {
pr_err("Could not find an available irq for trigger %s, CONFIG_IIO_CONSUMERS_PER_TRIGGER=%d limit might be exceeded\n",
trig->name, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
goto out_put_module; goto out_put_module;
}
/* Request irq */ /* Request irq */
ret = request_threaded_irq(pf->irq, pf->h, pf->thread, ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/* /*
* cros_ec_light_prox - Driver for light and prox sensors behing CrosEC. * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC.
* *
* Copyright (C) 2017 Google, Inc * Copyright (C) 2017 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/ */
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/common/cros_ec_sensors_core.h>
...@@ -28,7 +19,6 @@ ...@@ -28,7 +19,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h>
/* /*
* We only represent one entry for light or proximity. EC is merging different * We only represent one entry for light or proximity. EC is merging different
......
This diff is collapsed.
...@@ -733,9 +733,8 @@ static int ak8974_probe(struct i2c_client *i2c, ...@@ -733,9 +733,8 @@ static int ak8974_probe(struct i2c_client *i2c,
ak8974->i2c = i2c; ak8974->i2c = i2c;
mutex_init(&ak8974->lock); mutex_init(&ak8974->lock);
ret = of_iio_read_mount_matrix(&i2c->dev, ret = iio_read_mount_matrix(&i2c->dev, "mount-matrix",
"mount-matrix", &ak8974->orientation);
&ak8974->orientation);
if (ret) if (ret)
return ret; return ret;
......
This diff is collapsed.
This diff is collapsed.
...@@ -43,6 +43,7 @@ struct hmc5843_data { ...@@ -43,6 +43,7 @@ struct hmc5843_data {
struct mutex lock; struct mutex lock;
struct regmap *regmap; struct regmap *regmap;
const struct hmc5843_chip_info *variant; const struct hmc5843_chip_info *variant;
struct iio_mount_matrix orientation;
__be16 buffer[8]; __be16 buffer[8];
}; };
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_ISL29501) += isl29501.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_MB1232) += mb1232.o
obj-$(CONFIG_RFD77402) += rfd77402.o obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o obj-$(CONFIG_SRF08) += srf08.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment