Staging / IIO patches for 5.5-rc1

Here is the big staging and iio set of patches for the 5.5-rc1 release.
 
 It's the usual huge collection of cleanup patches all over the
 drivers/staging/ area, along with a new staging driver, and a bunch of
 new IIO drivers as well.
 
 Full details are in the shortlog, but all of these have been in
 linux-next for a long time with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXd6lVQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylFnwCgyvZ62uUyQTRey0zvNTe3I4fY9L4AnAnrz3ZC
 U6ZA2+Uj3O6qhAr5frRu
 =uv8S
 -----END PGP SIGNATURE-----

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

Pull staging / iio updates from Greg KH:
 "Here is the big staging and iio set of patches for the 5.5-rc1
  release.

  It's the usual huge collection of cleanup patches all over the
  drivers/staging/ area, along with a new staging driver, and a bunch of
  new IIO drivers as well.

  Full details are in the shortlog, but all of these have been in
  linux-next for a long time with no reported issues"

* tag 'staging-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (548 commits)
  staging: vchiq: Have vchiq_dump_* functions return an error code
  staging: vchiq: Refactor indentation in vchiq_dump_* functions
  staging: fwserial: Fix Kconfig indentation (seven spaces)
  staging: vchiq_dump: Replace min with min_t
  staging: vchiq: Fix block comment format in vchiq_dump()
  staging: octeon: indent with tabs instead of spaces
  staging: comedi: usbduxfast: usbduxfast_ai_cmdtest rounding error
  staging: most: core: remove sysfs attr remove_link
  staging: vc04: Fix Kconfig indentation
  staging: pi433: Fix Kconfig indentation
  staging: nvec: Fix Kconfig indentation
  staging: most: Fix Kconfig indentation
  staging: fwserial: Fix Kconfig indentation
  staging: fbtft: Fix Kconfig indentation
  fbtft: Drop OF dependency
  fbtft: Make use of device property API
  fbtft: Drop useless #ifdef CONFIG_OF and dead code
  fbtft: Describe function parameters in kernel-doc
  fbtft: Make sure string is NULL terminated
  staging: rtl8723bs: remove set but not used variable 'change', 'pos'
  ...
This commit is contained in:
Linus Torvalds 2019-11-27 10:57:52 -08:00
commit 0dd09bc02c
393 changed files with 24845 additions and 9583 deletions

View File

@ -753,6 +753,8 @@ What: /sys/.../events/in_illuminance0_thresh_falling_value
what: /sys/.../events/in_illuminance0_thresh_rising_value
what: /sys/.../events/in_proximity0_thresh_falling_value
what: /sys/.../events/in_proximity0_thresh_rising_value
What: /sys/.../events/in_illuminance_thresh_rising_value
What: /sys/.../events/in_illuminance_thresh_falling_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@ -972,6 +974,7 @@ What: /sys/.../events/in_activity_jogging_thresh_rising_period
What: /sys/.../events/in_activity_jogging_thresh_falling_period
What: /sys/.../events/in_activity_running_thresh_rising_period
What: /sys/.../events/in_activity_running_thresh_falling_period
What: /sys/.../events/in_illuminance_thresh_either_period
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@ -1715,3 +1718,11 @@ Description:
Mass concentration reading of particulate matter in ug / m3.
pmX consists of particles with aerodynamic diameter less or
equal to X micrometers.
What: /sys/bus/iio/devices/iio:deviceX/events/in_illuminance_period_available
Date: November 2019
KernelVersion: 5.4
Contact: linux-iio@vger.kernel.org
Description:
List of valid periods (in seconds) for which the light intensity
must be above the threshold level before interrupt is asserted.

View File

@ -0,0 +1,39 @@
What: /sys/bus/iio/devices/iio:deviceX/ac_excitation_en
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Reading gives the state of AC excitation.
Writing '1' enables AC excitation.
What: /sys/bus/iio/devices/iio:deviceX/bridge_switch_en
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
This bridge switch is used to disconnect it when there is a
need to minimize the system current consumption.
Reading gives the state of the bridge switch.
Writing '1' enables the bridge switch.
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Initiates the system calibration procedure. This is done on a
single channel at a time. Write '1' to start the calibration.
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode_available
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Reading returns a list with the possible calibration modes.
There are two available options:
"zero_scale" - calibrate to zero scale
"full_scale" - calibrate to full scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
Sets up the calibration mode used in the system calibration
procedure. Reading returns the current calibration mode.
Writing sets the system calibration mode.

View File

@ -0,0 +1,50 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/counter/ti-eqep.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP) Module
maintainers:
- David Lechner <david@lechnology.com>
properties:
compatible:
const: ti,am3352-eqep
reg:
maxItems: 1
interrupts:
description: The eQEP event interrupt
maxItems: 1
clocks:
description: The clock that determines the SYSCLKOUT rate for the eQEP
peripheral.
maxItems: 1
clock-names:
const: sysclkout
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
additionalProperties: false
examples:
- |
eqep0: counter@180 {
compatible = "ti,am3352-eqep";
reg = <0x180 0x80>;
clocks = <&l4ls_gclk>;
clock-names = "sysclkout";
interrupts = <79>;
};
...

View File

@ -0,0 +1,104 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,ad7292.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7292 10-Bit Monitor and Control System
maintainers:
- Marcelo Schmitt <marcelo.schmitt1@gmail.com>
description: |
Analog Devices AD7292 10-Bit Monitor and Control System with ADC, DACs,
Temperature Sensor, and GPIOs
Specifications about the part can be found at:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7292.pdf
properties:
compatible:
enum:
- adi,ad7292
reg:
maxItems: 1
vref-supply:
description: |
The regulator supply for ADC and DAC reference voltage.
spi-cpha: true
'#address-cells':
const: 1
'#size-cells':
const: 0
required:
- compatible
- reg
- spi-cpha
patternProperties:
"^channel@[0-7]$":
type: object
description: |
Represents the external channels which are connected to the ADC.
See Documentation/devicetree/bindings/iio/adc/adc.txt.
properties:
reg:
description: |
The channel number. It can have up to 8 channels numbered from 0 to 7.
items:
maximum: 7
diff-channels:
description: see Documentation/devicetree/bindings/iio/adc/adc.txt
maxItems: 1
required:
- reg
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ad7292: adc@0 {
compatible = "adi,ad7292";
reg = <0>;
spi-max-frequency = <25000000>;
vref-supply = <&adc_vref>;
spi-cpha;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
diff-channels = <0 1>;
};
channel@2 {
reg = <2>;
};
channel@3 {
reg = <3>;
};
channel@4 {
reg = <4>;
};
channel@5 {
reg = <5>;
};
channel@6 {
reg = <6>;
};
channel@7 {
reg = <7>;
};
};
};

View File

@ -5,6 +5,7 @@ Required properties:
- compatible: Should be one of:
* ingenic,jz4725b-adc
* ingenic,jz4740-adc
* ingenic,jz4770-adc
- reg: ADC controller registers location and length.
- clocks: phandle to the SoC's ADC clock.
- clock-names: Must be set to "adc".

View File

@ -1,20 +0,0 @@
* Maxim 1027/1029/1031 Analog to Digital Converter (ADC)
Required properties:
- compatible: Should be "maxim,max1027" or "maxim,max1029" or "maxim,max1031"
- reg: SPI chip select number for the device
- interrupts: IRQ line for the ADC
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "maxim,max1027";
reg = <0>;
interrupt-parent = <&gpio5>;
interrupts = <15 IRQ_TYPE_EDGE_RISING>;
spi-max-frequency = <1000000>;
};

View File

@ -1,30 +0,0 @@
* Microchip MCP3911 Dual channel analog front end (ADC)
Required properties:
- compatible: Should be "microchip,mcp3911"
- reg: SPI chip select number for the device
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt.
Max frequency for this chip is 20MHz.
Optional properties:
- clocks: Phandle and clock identifier for sampling clock
- interrupt-parent: Phandle to the parent interrupt controller
- interrupts: IRQ line for the ADC
- microchip,device-addr: Device address when multiple MCP3911 chips are present on the
same SPI bus. Valid values are 0-3. Defaults to 0.
- vref-supply: Phandle to the external reference voltage supply.
Example:
adc@0 {
compatible = "microchip,mcp3911";
reg = <0>;
interrupt-parent = <&gpio5>;
interrupts = <15 IRQ_TYPE_EDGE_RISING>;
spi-max-frequency = <20000000>;
microchip,device-addr = <0>;
vref-supply = <&vref_reg>;
clocks = <&xtal>;
};

View File

@ -0,0 +1,71 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
# Copyright 2019 Marcus Folkesson <marcus.folkesson@gmail.com>
%YAML 1.2
---
$id: "http://devicetree.org/schemas/bindings/iio/adc/microchip,mcp3911.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Microchip MCP3911 Dual channel analog front end (ADC)
maintainers:
- Marcus Folkesson <marcus.folkesson@gmail.com>
- Kent Gustavsson <nedo80@gmail.com>
description: |
Bindings for the Microchip MCP3911 Dual channel ADC device. Datasheet can be
found here: https://ww1.microchip.com/downloads/en/DeviceDoc/20002286C.pdf
properties:
compatible:
enum:
- microchip,mcp3911
reg:
maxItems: 1
spi-max-frequency:
maximum: 20000000
clocks:
description: |
Phandle and clock identifier for external sampling clock.
If not specified, the internal crystal oscillator will be used.
maxItems: 1
interrupts:
description: IRQ line of the ADC
maxItems: 1
microchip,device-addr:
description: Device address when multiple MCP3911 chips are present on the same SPI bus.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 1, 2, 3]
- default: 0
vref-supply:
description: |
Phandle to the external reference voltage supply.
If not specified, the internal voltage reference (1.2V) will be used.
required:
- compatible
- reg
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "microchip,mcp3911";
reg = <0>;
interrupt-parent = <&gpio5>;
interrupts = <15 2>;
spi-max-frequency = <20000000>;
microchip,device-addr = <0>;
vref-supply = <&vref_reg>;
clocks = <&xtal>;
};
};

View File

@ -53,6 +53,8 @@ Optional properties:
analog input switches on stm32mp1.
- st,syscfg: Phandle to system configuration controller. It can be used to
control the analog circuitry on stm32mp1.
- st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog
circuitry.
Contents of a stm32 adc child node:
-----------------------------------

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
# Copyright 2019 Marcus Folkesson <marcus.folkesson@gmail.com>
%YAML 1.2
---
$id: "http://devicetree.org/schemas/bindings/iio/dac/lltc,ltc1660.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Linear Technology Micropower octal 8-Bit and 10-Bit DACs
maintainers:
- Marcus Folkesson <marcus.folkesson@gmail.com>
description: |
Bindings for the Linear Technology Micropower octal 8-Bit and 10-Bit DAC.
Datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/166560fa.pdf
properties:
compatible:
enum:
- lltc,ltc1660
- lltc,ltc1665
reg:
maxItems: 1
spi-max-frequency:
maximum: 5000000
vref-supply:
description: Phandle to the external reference voltage supply.
required:
- compatible
- reg
- vref-supply
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "lltc,ltc1660";
reg = <0>;
spi-max-frequency = <5000000>;
vref-supply = <&vref_reg>;
};
};

View File

@ -1,21 +0,0 @@
* Linear Technology Micropower octal 8-Bit and 10-Bit DACs
Required properties:
- compatible: Must be one of the following:
"lltc,ltc1660"
"lltc,ltc1665"
- reg: SPI chip select number for the device
- vref-supply: Phandle to the voltage reference supply
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt.
Max frequency for this chip is 5 MHz.
Example:
dac@0 {
compatible = "lltc,ltc1660";
reg = <0>;
spi-max-frequency = <5000000>;
vref-supply = <&vref_reg>;
};

View File

@ -18,12 +18,17 @@ Required properties:
with a single IIO output and 1 for nodes with multiple
IIO outputs.
Optional properties:
label: A symbolic name for the device.
Example for a simple configuration with no trigger:
adc: voltage-sensor@35 {
compatible = "maxim,max1139";
reg = <0x35>;
#io-channel-cells = <1>;
label = "voltage_feedback_group1";
};
Example for a configuration with trigger:

View File

@ -21,6 +21,7 @@ Required properties:
bindings.
Optional properties:
- vdd-supply: regulator phandle for VDD supply
- vddio-supply: regulator phandle for VDDIO supply
- mount-matrix: an optional 3x3 mounting rotation matrix
- i2c-gate node. These devices also support an auxiliary i2c bus. This is

View File

@ -0,0 +1,76 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/nxp,fxos8700.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale FXOS8700 Inertial Measurement Unit
maintainers:
- Robert Jones <rjones@gateworks.com>
description: |
Accelerometer and magnetometer combo device with an i2c and SPI interface.
https://www.nxp.com/products/sensors/motion-sensors/6-axis/digital-motion-sensor-3d-accelerometer-2g-4g-8g-plus-3d-magnetometer:FXOS8700CQ
properties:
compatible:
enum:
- nxp,fxos8700
reg:
maxItems: 1
interrupts:
minItems: 1
maxItems: 2
interrupt-names:
minItems: 1
maxItems: 2
items:
enum:
- INT1
- INT2
drive-open-drain:
type: boolean
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
fxos8700@1e {
compatible = "nxp,fxos8700";
reg = <0x1e>;
interrupt-parent = <&gpio2>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
};
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
fxos8700@0 {
compatible = "nxp,fxos8700";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT2";
};
};

View File

@ -14,6 +14,8 @@ Required properties:
"st,lsm6ds3tr-c"
"st,ism330dhcx"
"st,lsm9ds1-imu"
"st,lsm6ds0"
"st,lsm6dsrx"
- reg: i2c address of the sensor / spi cs line
Optional properties:
@ -31,6 +33,7 @@ Optional properties:
- interrupts: interrupt mapping for IRQ. It should be configured with
flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
IRQ_TYPE_EDGE_FALLING.
- wakeup-source: Enables wake up of host system on event.
Refer to interrupt-controller/interrupts.txt for generic interrupt
client node bindings.

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/adux1020.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADUX1020 Photometric sensor
maintainers:
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description: |
Photometric sensor over an i2c interface.
https://www.analog.com/media/en/technical-documentation/data-sheets/ADUX1020.pdf
properties:
compatible:
enum:
- adi,adux1020
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
adux1020@64 {
compatible = "adi,adux1020";
reg = <0x64>;
interrupt-parent = <&msmgpio>;
interrupts = <24 IRQ_TYPE_LEVEL_HIGH>;
};
};
...

View File

@ -1,18 +0,0 @@
ROHM BH1750 - ALS, Ambient light sensor
Required properties:
- compatible: Must be one of:
"rohm,bh1710"
"rohm,bh1715"
"rohm,bh1721"
"rohm,bh1750"
"rohm,bh1751"
- reg: the I2C address of the sensor
Example:
light-sensor@23 {
compatible = "rohm,bh1750";
reg = <0x23>;
};

View File

@ -0,0 +1,43 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/bh1750.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BH1750 ambient light sensor
maintainers:
- Tomasz Duszynski <tduszyns@gmail.com>
description: |
Ambient light sensor with an i2c interface.
properties:
compatible:
enum:
- rohm,bh1710
- rohm,bh1715
- rohm,bh1721
- rohm,bh1750
- rohm,bh1751
reg:
maxItems: 1
required:
- compatible
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
light-sensor@23 {
compatible = "rohm,bh1750";
reg = <0x23>;
};
};
...

View File

@ -0,0 +1,62 @@
# SPDX-License-Identifier: GPL-2.0+
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/veml6030.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: VEML6030 Ambient Light Sensor (ALS)
maintainers:
- Rishi Gupta <gupt21@gmail.com>
description: |
Bindings for the ambient light sensor veml6030 from Vishay
Semiconductors over an i2c interface.
Irrespective of whether interrupt is used or not, application
can get the ALS and White channel reading from IIO raw interface.
If the interrupts are used, application will receive an IIO event
whenever configured threshold is crossed.
Specifications about the sensor can be found at:
https://www.vishay.com/docs/84366/veml6030.pdf
properties:
compatible:
enum:
- vishay,veml6030
reg:
description:
I2C address of the device.
enum:
- 0x10 # ADDR pin pulled down
- 0x48 # ADDR pin pulled up
interrupts:
description:
interrupt mapping for IRQ. Configure with IRQ_TYPE_LEVEL_LOW.
Refer to interrupt-controller/interrupts.txt for generic
interrupt client node bindings.
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
light-sensor@10 {
compatible = "vishay,veml6030";
reg = <0x10>;
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
};
};
...

View File

@ -1,29 +0,0 @@
* 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>;
};

View File

@ -0,0 +1,60 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/maxbotix,mb1232.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MaxBotix I2CXL-MaxSonar ultrasonic distance sensor
maintainers:
- Andreas Klinger <ak@it-klinger.de>
description: |
MaxBotix I2CXL-MaxSonar ultrasonic distance sensor of type mb1202,
mb1212, mb1222, mb1232, mb1242, mb7040 or mb7137 using the i2c interface
for ranging
Specifications about the devices can be found at:
https://www.maxbotix.com/documents/I2CXL-MaxSonar-EZ_Datasheet.pdf
properties:
compatible:
enum:
- maxbotix,mb1202
- maxbotix,mb1212
- maxbotix,mb1222
- maxbotix,mb1232
- maxbotix,mb1242
- maxbotix,mb7040
- maxbotix,mb7137
reg:
maxItems: 1
interrupts:
description:
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.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
proximity@70 {
compatible = "maxbotix,mb1232";
reg = <0x70>;
interrupt-parent = <&gpio2>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
};
};

View File

@ -0,0 +1,480 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/temperature/adi,ltc2983.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices LTC2983 Multi-sensor Temperature system
maintainers:
- Nuno Sá <nuno.sa@analog.com>
description: |
Analog Devices LTC2983 Multi-Sensor Digital Temperature Measurement System
https://www.analog.com/media/en/technical-documentation/data-sheets/2983fc.pdf
properties:
compatible:
enum:
- adi,ltc2983
reg:
maxItems: 1
interrupts:
maxItems: 1
adi,mux-delay-config-us:
description:
The LTC2983 performs 2 or 3 internal conversion cycles per temperature
result. Each conversion cycle is performed with different excitation and
input multiplexer configurations. Prior to each conversion, these
excitation circuits and input switch configurations are changed and an
internal 1ms delay ensures settling prior to the conversion cycle in most
cases. An extra delay can be configured using this property. The value is
rounded to nearest 100us.
maximum: 255
adi,filter-notch-freq:
description:
Set's the default setting of the digital filter. The default is
simultaneous 50/60Hz rejection.
0 - 50/60Hz rejection
1 - 60Hz rejection
2 - 50Hz rejection
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 0
maximum: 2
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
"@([1-9]|1[0-9]|20)$":
type: object
properties:
reg:
description:
The channel number. It can be connected to one of the 20 channels of
the device.
minimum: 1
maximum: 20
adi,sensor-type:
description: Identifies the type of sensor connected to the device.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- reg
- adi,sensor-type
"^thermocouple@":
type: object
description:
Represents a thermocouple sensor which is connected to one of the device
channels.
properties:
adi,sensor-type:
description: |
1 - Type J Thermocouple
2 - Type K Thermocouple
3 - Type E Thermocouple
4 - Type N Thermocouple
5 - Type R Thermocouple
6 - Type S Thermocouple
7 - Type T Thermocouple
8 - Type B Thermocouple
9 - Custom Thermocouple
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 9
adi,single-ended:
description:
Boolean property which set's the thermocouple as single-ended.
type: boolean
adi,sensor-oc-current-microamp:
description:
This property set's the pulsed current value applied during
open-circuit detect.
enum: [10, 100, 500, 1000]
adi,cold-junction-handle:
description:
Phandle which points to a sensor object responsible for measuring
the thermocouple cold junction temperature.
$ref: "/schemas/types.yaml#/definitions/phandle"
adi,custom-thermocouple:
description:
This is a table, where each entry should be a pair of
voltage(mv)-temperature(K). The entries must be given in nv and uK
so that, the original values must be multiplied by 1000000. For
more details look at table 69 and 70.
Note should be signed, but dtc doesn't currently maintain the
sign.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint64-matrix
items:
minItems: 3
maxItems: 64
items:
minItems: 2
maxItems: 2
"^diode@":
type: object
description:
Represents a diode sensor which is connected to one of the device
channels.
properties:
adi,sensor-type:
description: Identifies the sensor as a diode.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
const: 28
adi,single-ended:
description: Boolean property which set's the diode as single-ended.
type: boolean
adi,three-conversion-cycles:
description:
Boolean property which set's three conversion cycles removing
parasitic resistance effects between the LTC2983 and the diode.
type: boolean
adi,average-on:
description:
Boolean property which enables a running average of the diode
temperature reading. This reduces the noise when the diode is used
as a cold junction temperature element on an isothermal block
where temperatures change slowly.
type: boolean
adi,excitation-current-microamp:
description:
This property controls the magnitude of the excitation current
applied to the diode. Depending on the number of conversions
cycles, this property will assume different predefined values on
each cycle. Just set the value of the first cycle (1l).
enum: [10, 20, 40, 80]
adi,ideal-factor-value:
description:
This property sets the diode ideality factor. The real value must
be multiplied by 1000000 to remove the fractional part. For more
information look at table 20 of the datasheet.
$ref: /schemas/types.yaml#/definitions/uint32
"^rtd@":
type: object
description:
Represents a rtd sensor which is connected to one of the device channels.
properties:
reg:
minimum: 2
maximum: 20
adi,sensor-type:
description: |
10 - RTD PT-10
11 - RTD PT-50
12 - RTD PT-100
13 - RTD PT-200
14 - RTD PT-500
15 - RTD PT-1000
16 - RTD PT-1000 (0.00375)
17 - RTD NI-120
18 - RTD Custom
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
minimum: 10
maximum: 18
adi,rsense-handle:
description:
Phandle pointing to a rsense object associated with this RTD.
$ref: "/schemas/types.yaml#/definitions/phandle"
adi,number-of-wires:
description:
Identifies the number of wires used by the RTD. Setting this
property to 5 means 4 wires with Kelvin Rsense.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [2, 3, 4, 5]
adi,rsense-share:
description:
Boolean property which enables Rsense sharing, where one sense
resistor is used for multiple 2-, 3-, and/or 4-wire RTDs.
type: boolean
adi,current-rotate:
description:
Boolean property which enables excitation current rotation to
automatically remove parasitic thermocouple effects. Note that
this property is not allowed for 2- and 3-wire RTDs.
type: boolean
adi,excitation-current-microamp:
description:
This property controls the magnitude of the excitation current
applied to the RTD.
enum: [5, 10, 25, 50, 100, 250, 500, 1000]
adi,rtd-curve:
description:
This property set the RTD curve used and the corresponding
Callendar-VanDusen constants. Look at table 30 of the datasheet.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 0
maximum: 3
adi,custom-rtd:
description:
This is a table, where each entry should be a pair of
resistance(ohm)-temperature(K). The entries added here are in uohm
and uK. For more details values look at table 74 and 75.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint64-matrix
items:
minItems: 3
maxItems: 64
items:
minItems: 2
maxItems: 2
required:
- adi,rsense-handle
dependencies:
adi,current-rotate: [ adi,rsense-share ]
"^thermistor@":
type: object
description:
Represents a thermistor sensor which is connected to one of the device
channels.
properties:
adi,sensor-type:
description:
19 - Thermistor 44004/44033 2.252kohm at 25°C
20 - Thermistor 44005/44030 3kohm at 25°C
21 - Thermistor 44007/44034 5kohm at 25°C
22 - Thermistor 44006/44031 10kohm at 25°C
23 - Thermistor 44008/44032 30kohm at 25°C
24 - Thermistor YSI 400 2.252kohm at 25°C
25 - Thermistor Spectrum 1003k 1kohm
26 - Thermistor Custom Steinhart-Hart
27 - Custom Thermistor
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
minimum: 19
maximum: 27
adi,rsense-handle:
description:
Phandle pointing to a rsense object associated with this
thermistor.
$ref: "/schemas/types.yaml#/definitions/phandle"
adi,single-ended:
description:
Boolean property which set's the thermistor as single-ended.
type: boolean
adi,rsense-share:
description:
Boolean property which enables Rsense sharing, where one sense
resistor is used for multiple thermistors. Note that this property
is ignored if adi,single-ended is set.
type: boolean
adi,current-rotate:
description:
Boolean property which enables excitation current rotation to
automatically remove parasitic thermocouple effects.
type: boolean
adi,excitation-current-nanoamp:
description:
This property controls the magnitude of the excitation current
applied to the thermistor. Value 0 set's the sensor in auto-range
mode.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- enum: [0, 250, 500, 1000, 5000, 10000, 25000, 50000, 100000,
250000, 500000, 1000000]
adi,custom-thermistor:
description:
This is a table, where each entry should be a pair of
resistance(ohm)-temperature(K). The entries added here are in uohm
and uK only for custom thermistors. For more details look at table
78 and 79.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint64-matrix
items:
minItems: 3
maxItems: 64
items:
minItems: 2
maxItems: 2
adi,custom-steinhart:
description:
Steinhart-Hart coefficients are also supported and can
be programmed into the device memory using this property. For
Steinhart sensors the coefficients are given in the raw
format. Look at table 82 for more information.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
items:
minItems: 6
maxItems: 6
required:
- adi,rsense-handle
dependencies:
adi,current-rotate: [ adi,rsense-share ]
"^adc@":
type: object
description: Represents a channel which is being used as a direct adc.
properties:
adi,sensor-type:
description: Identifies the sensor as a direct adc.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
const: 30
adi,single-ended:
description: Boolean property which set's the adc as single-ended.
type: boolean
"^rsense@":
type: object
description:
Represents a rsense which is connected to one of the device channels.
Rsense are used by thermistors and RTD's.
properties:
reg:
minimum: 2
maximum: 20
adi,sensor-type:
description: Identifies the sensor as a rsense.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
const: 29
adi,rsense-val-milli-ohms:
description:
Sets the value of the sense resistor. Look at table 20 of the
datasheet for information.
required:
- adi,rsense-val-milli-ohms
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
sensor_ltc2983: ltc2983@0 {
compatible = "adi,ltc2983";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <20 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
thermocouple@18 {
reg = <18>;
adi,sensor-type = <8>; //Type B
adi,sensor-oc-current-microamp = <10>;
adi,cold-junction-handle = <&diode5>;
};
diode5: diode@5 {
reg = <5>;
adi,sensor-type = <28>;
};
rsense2: rsense@2 {
reg = <2>;
adi,sensor-type = <29>;
adi,rsense-val-milli-ohms = <1200000>; //1.2Kohms
};
rtd@14 {
reg = <14>;
adi,sensor-type = <15>; //PT1000
/*2-wire, internal gnd, no current rotation*/
adi,number-of-wires = <2>;
adi,rsense-share;
adi,excitation-current-microamp = <500>;
adi,rsense-handle = <&rsense2>;
};
adc@10 {
reg = <10>;
adi,sensor-type = <30>;
adi,single-ended;
};
thermistor@12 {
reg = <12>;
adi,sensor-type = <26>; //Steinhart
adi,rsense-handle = <&rsense2>;
adi,custom-steinhart = <0x00F371EC 0x12345678
0x2C0F8733 0x10018C66 0xA0FEACCD
0x90021D99>; //6 entries
};
thermocouple@20 {
reg = <20>;
adi,sensor-type = <9>; //custom thermocouple
adi,single-ended;
adi,custom-thermocouple = /bits/ 64
<(-50220000) 0
(-30200000) 99100000
(-5300000) 135400000
0 273150000
40200000 361200000
55300000 522100000
88300000 720300000
132200000 811200000
188700000 922500000
460400000 1000000000>; //10 pairs
};
};
};
...

View File

@ -114,6 +114,18 @@ properties:
- isil,isl68137
# 5 Bit Programmable, Pulse-Width Modulator
- maxim,ds1050
# 10-bit 8 channels 300ks/s SPI ADC with temperature sensor
- maxim,max1027
# 10-bit 12 channels 300ks/s SPI ADC with temperature sensor
- maxim,max1029
# 10-bit 16 channels 300ks/s SPI ADC with temperature sensor
- maxim,max1031
# 12-bit 8 channels 300ks/s SPI ADC with temperature sensor
- maxim,max1227
# 12-bit 12 channels 300ks/s SPI ADC with temperature sensor
- maxim,max1229
# 12-bit 16 channels 300ks/s SPI ADC with temperature sensor
- maxim,max1231
# Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
- maxim,max1237
# PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion

View File

@ -7,7 +7,7 @@ Generic Counter Interface
Introduction
============
Counter devices are prevalent within a diverse spectrum of industries.
Counter devices are prevalent among a diverse spectrum of industries.
The ubiquitous presence of these devices necessitates a common interface
and standard of interaction and exposure. This driver API attempts to
resolve the issue of duplicate code found among existing counter device
@ -26,23 +26,72 @@ the Generic Counter interface.
There are three core components to a counter:
* Count:
Count data for a set of Signals.
* Signal:
Input data that is evaluated by the counter to determine the count
data.
Stream of data to be evaluated by the counter.
* Synapse:
The association of a Signal with a respective Count.
Association of a Signal, and evaluation trigger, with a Count.
* Count:
Accumulation of the effects of connected Synapses.
SIGNAL
------
A Signal represents a stream of data. This is the input data that is
evaluated by the counter to determine the count data; e.g. a quadrature
signal output line of a rotary encoder. Not all counter devices provide
user access to the Signal data, so exposure is optional for drivers.
When the Signal data is available for user access, the Generic Counter
interface provides the following available signal values:
* SIGNAL_LOW:
Signal line is in a low state.
* SIGNAL_HIGH:
Signal line is in a high state.
A Signal may be associated with one or more Counts.
SYNAPSE
-------
A Synapse represents the association of a Signal with a Count. Signal
data affects respective Count data, and the Synapse represents this
relationship.
The Synapse action mode specifies the Signal data condition that
triggers the respective Count's count function evaluation to update the
count data. The Generic Counter interface provides the following
available action modes:
* None:
Signal does not trigger the count function. In Pulse-Direction count
function mode, this Signal is evaluated as Direction.
* Rising Edge:
Low state transitions to high state.
* Falling Edge:
High state transitions to low state.
* Both Edges:
Any state transition.
A counter is defined as a set of input signals associated with count
data that are generated by the evaluation of the state of the associated
input signals as defined by the respective count functions. Within the
context of the Generic Counter interface, a counter consists of Counts
each associated with a set of Signals, whose respective Synapse
instances represent the count function update conditions for the
associated Counts.
A Synapse associates one Signal with one Count.
COUNT
-----
A Count represents the count data for a set of Signals. The Generic
Counter interface provides the following available count data types:
* COUNT_POSITION:
Unsigned integer value representing position.
A Count represents the accumulation of the effects of connected
Synapses; i.e. the count data for a set of Signals. The Generic
Counter interface represents the count data as a natural number.
A Count has a count function mode which represents the update behavior
for the count data. The Generic Counter interface provides the following
@ -86,60 +135,7 @@ available count function modes:
Any state transition on either quadrature pair signals updates the
respective count. Quadrature encoding determines the direction.
A Count has a set of one or more associated Signals.
SIGNAL
------
A Signal represents a counter input data; this is the input data that is
evaluated by the counter to determine the count data; e.g. a quadrature
signal output line of a rotary encoder. Not all counter devices provide
user access to the Signal data.
The Generic Counter interface provides the following available signal
data types for when the Signal data is available for user access:
* SIGNAL_LEVEL:
Signal line state level. The following states are possible:
- SIGNAL_LEVEL_LOW:
Signal line is in a low state.
- SIGNAL_LEVEL_HIGH:
Signal line is in a high state.
A Signal may be associated with one or more Counts.
SYNAPSE
-------
A Synapse represents the association of a Signal with a respective
Count. Signal data affects respective Count data, and the Synapse
represents this relationship.
The Synapse action mode specifies the Signal data condition which
triggers the respective Count's count function evaluation to update the
count data. The Generic Counter interface provides the following
available action modes:
* None:
Signal does not trigger the count function. In Pulse-Direction count
function mode, this Signal is evaluated as Direction.
* Rising Edge:
Low state transitions to high state.
* Falling Edge:
High state transitions to low state.
* Both Edges:
Any state transition.
A counter is defined as a set of input signals associated with count
data that are generated by the evaluation of the state of the associated
input signals as defined by the respective count functions. Within the
context of the Generic Counter interface, a counter consists of Counts
each associated with a set of Signals, whose respective Synapse
instances represent the count function update conditions for the
associated Counts.
A Count has a set of one or more associated Synapses.
Paradigm
========
@ -286,10 +282,36 @@ if device memory-managed registration is desired.
Extension sysfs attributes can be created for auxiliary functionality
and data by passing in defined counter_device_ext, counter_count_ext,
and counter_signal_ext structures. In these cases, the
counter_device_ext structure is used for global configuration of the
respective Counter device, while the counter_count_ext and
counter_signal_ext structures allow for auxiliary exposure and
configuration of a specific Count or Signal respectively.
counter_device_ext structure is used for global/miscellaneous exposure
and configuration of the respective Counter device, while the
counter_count_ext and counter_signal_ext structures allow for auxiliary
exposure and configuration of a specific Count or Signal respectively.
Determining the type of extension to create is a matter of scope.
* Signal extensions are attributes that expose information/control
specific to a Signal. These types of attributes will exist under a
Signal's directory in sysfs.
For example, if you have an invert feature for a Signal, you can have
a Signal extension called "invert" that toggles that feature:
/sys/bus/counter/devices/counterX/signalY/invert
* Count extensions are attributes that expose information/control
specific to a Count. These type of attributes will exist under a
Count's directory in sysfs.
For example, if you want to pause/unpause a Count from updating, you
can have a Count extension called "enable" that toggles such:
/sys/bus/counter/devices/counterX/countY/enable
* Device extensions are attributes that expose information/control
non-specific to a particular Count or Signal. This is where you would
put your global features or other miscellanous functionality.
For example, if your device has an overtemp sensor, you can report the
chip overheated via a device extension called "error_overtemp":
/sys/bus/counter/devices/counterX/error_overtemp
Architecture
============

View File

@ -901,6 +901,14 @@ S: Supported
F: drivers/iio/adc/ad7124.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
ANALOG DEVICES INC AD7292 DRIVER
M: Marcelo Schmitt <marcelo.schmitt1@gmail.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7292.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
ANALOG DEVICES INC AD7606 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
M: Beniamin Bia <beniamin.bia@analog.com>
@ -6182,6 +6190,7 @@ F: include/uapi/linux/mii.h
EXFAT FILE SYSTEM
M: Valdis Kletnieks <valdis.kletnieks@vt.edu>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: drivers/staging/exfat/
@ -9701,9 +9710,17 @@ LTC1660 DAC DRIVER
M: Marcus Folkesson <marcus.folkesson@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/dac/ltc1660.txt
F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml
F: drivers/iio/dac/ltc1660.c
LTC2983 IIO TEMPERATURE DRIVER
M: Nuno Sá <nuno.sa@analog.com>
W: http://ez.analog.com/community/linux-device-drivers
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/temperature/ltc2983.c
F: Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
LTC4261 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
@ -10819,7 +10836,7 @@ M: Kent Gustavsson <kent@minoris.se>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/adc/mcp3911.c
F: Documentation/devicetree/bindings/iio/adc/mcp3911.txt
F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml
MICROCHIP NAND DRIVER
M: Tudor Ambarus <tudor.ambarus@microchip.com>
@ -14072,6 +14089,12 @@ L: linux-serial@vger.kernel.org
S: Odd Fixes
F: drivers/tty/serial/rp2.*
ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER
M: Tomasz Duszynski <tduszyns@gmail.com>
S: Maintained
F: drivers/iio/light/bh1750.c
F: Documentation/devicetree/bindings/iio/light/bh1750.yaml
ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
M: Marek Vasut <marek.vasut+renesas@gmail.com>
L: linux-kernel@vger.kernel.org
@ -14923,6 +14946,11 @@ S: Maintained
F: drivers/input/touchscreen/silead.c
F: drivers/platform/x86/touchscreen_dmi.c
SILICON LABS WIRELESS DRIVERS (for WFxxx series)
M: Jérôme Pouiller <jerome.pouiller@silabs.com>
S: Supported
F: drivers/staging/wfx/
SILICON MOTION SM712 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Teddy Wang <teddy.wang@siliconmotion.com>
@ -15588,6 +15616,14 @@ L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/staging/wilc1000/
STAGING - SEPS525 LCD CONTROLLER DRIVERS
M: Michael Hennerich <michael.hennerich@analog.com>
M: Beniamin Bia <beniamin.bia@analog.com>
L: linux-fbdev@vger.kernel.org
S: Supported
F: drivers/staging/fbtft/fb_seps525.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
STAGING SUBSYSTEM
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
@ -16330,6 +16366,12 @@ S: Maintained
F: drivers/media/platform/davinci/
F: include/media/davinci/
TI ENHANCED QUADRATURE ENCODER PULSE (eQEP) DRIVER
R: David Lechner <david@lechnology.com>
L: linux-iio@vger.kernel.org
F: Documentation/devicetree/bindings/counter/ti-eqep.yaml
F: drivers/counter/ti-eqep.c
TI ETHERNET SWITCH DRIVER (CPSW)
R: Grygorii Strashko <grygorii.strashko@ti.com>
L: linux-omap@vger.kernel.org

View File

@ -51,6 +51,7 @@ choice
select MIPS_GIC
select COMMON_CLK
select CLKSRC_MIPS_GIC
select HAVE_PCI if PCI_MT7621
endchoice
choice

View File

@ -150,6 +150,15 @@ config TEGRA_GMI
Driver for the Tegra Generic Memory Interface bus which can be used
to attach devices such as NOR, UART, FPGA and more.
config TI_PWMSS
bool
default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM || TI_EQEP)
help
PWM Subsystem driver support for AM33xx SOC.
PWM submodules require PWM config space access from submodule
drivers and require common parent driver support.
config TI_SYSC
bool "TI sysc interconnect target module driver"
depends on ARCH_OMAP2PLUS

View File

@ -27,6 +27,7 @@ obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o
obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o
obj-$(CONFIG_TI_PWMSS) += ti-pwmss.o
obj-$(CONFIG_TI_SYSC) += ti-sysc.o
obj-$(CONFIG_TS_NBUS) += ts-nbus.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o

View File

@ -562,11 +562,10 @@ static const struct iio_chan_spec quad8_channels[] = {
};
static int quad8_signal_read(struct counter_device *counter,
struct counter_signal *signal, struct counter_signal_read_value *val)
struct counter_signal *signal, enum counter_signal_value *val)
{
const struct quad8_iio *const priv = counter->priv;
unsigned int state;
enum counter_signal_level level;
/* Only Index signal levels can be read */
if (signal->id < 16)
@ -575,22 +574,19 @@ static int quad8_signal_read(struct counter_device *counter,
state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS)
& BIT(signal->id - 16);
level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW;
counter_signal_read_value_set(val, COUNTER_SIGNAL_LEVEL, &level);
*val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW;
return 0;
}
static int quad8_count_read(struct counter_device *counter,
struct counter_count *count, struct counter_count_read_value *val)
struct counter_count *count, unsigned long *val)
{
const struct quad8_iio *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
unsigned int flags;
unsigned int borrow;
unsigned int carry;
unsigned long position;
int i;
flags = inb(base_offset + 1);
@ -598,36 +594,27 @@ static int quad8_count_read(struct counter_device *counter,
carry = !!(flags & QUAD8_FLAG_CT);
/* Borrow XOR Carry effectively doubles count range */
position = (unsigned long)(borrow ^ carry) << 24;
*val = (unsigned long)(borrow ^ carry) << 24;
/* Reset Byte Pointer; transfer Counter to Output Latch */
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
base_offset + 1);
for (i = 0; i < 3; i++)
position |= (unsigned long)inb(base_offset) << (8 * i);
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position);
*val |= (unsigned long)inb(base_offset) << (8 * i);
return 0;
}
static int quad8_count_write(struct counter_device *counter,
struct counter_count *count, struct counter_count_write_value *val)
struct counter_count *count, unsigned long val)
{
const struct quad8_iio *const priv = counter->priv;
const int base_offset = priv->base + 2 * count->id;
int err;
unsigned long position;
int i;
err = counter_count_write_value_get(&position, COUNTER_COUNT_POSITION,
val);
if (err)
return err;
/* Only 24-bit values are supported */
if (position > 0xFFFFFF)
if (val > 0xFFFFFF)
return -EINVAL;
/* Reset Byte Pointer */
@ -635,7 +622,7 @@ static int quad8_count_write(struct counter_device *counter,
/* Counter can only be set via Preset Register */
for (i = 0; i < 3; i++)
outb(position >> (8 * i), base_offset);
outb(val >> (8 * i), base_offset);
/* Transfer Preset Register to Counter */
outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1);
@ -644,9 +631,9 @@ static int quad8_count_write(struct counter_device *counter,
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
/* Set Preset Register back to original value */
position = priv->preset[count->id];
val = priv->preset[count->id];
for (i = 0; i < 3; i++)
outb(position >> (8 * i), base_offset);
outb(val >> (8 * i), base_offset);
/* Reset Borrow, Carry, Compare, and Sign flags */
outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1);

View File

@ -49,6 +49,17 @@ config STM32_LPTIMER_CNT
To compile this driver as a module, choose M here: the
module will be called stm32-lptimer-cnt.
config TI_EQEP
tristate "TI eQEP counter driver"
depends on (SOC_AM33XX || COMPILE_TEST)
select REGMAP_MMIO
help
Select this option to enable the Texas Instruments Enhanced Quadrature
Encoder Pulse (eQEP) counter driver.
To compile this driver as a module, choose M here: the module will be
called ti-eqep.
config FTM_QUADDEC
tristate "Flex Timer Module Quadrature decoder driver"
depends on HAS_IOMEM && OF

View File

@ -8,4 +8,5 @@ obj-$(CONFIG_COUNTER) += counter.o
obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o
obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o
obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o
obj-$(CONFIG_TI_EQEP) += ti-eqep.o
obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o

View File

@ -220,86 +220,6 @@ ssize_t counter_device_enum_available_read(struct counter_device *counter,
}
EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
static const char *const counter_signal_level_str[] = {
[COUNTER_SIGNAL_LEVEL_LOW] = "low",
[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
};
/**
* counter_signal_read_value_set - set counter_signal_read_value data
* @val: counter_signal_read_value structure to set
* @type: property Signal data represents
* @data: Signal data
*
* This function sets an opaque counter_signal_read_value structure with the
* provided Signal data.
*/
void counter_signal_read_value_set(struct counter_signal_read_value *const val,
const enum counter_signal_value_type type,
void *const data)
{
if (type == COUNTER_SIGNAL_LEVEL)
val->len = sprintf(val->buf, "%s\n",
counter_signal_level_str[*(enum counter_signal_level *)data]);
else
val->len = 0;
}
EXPORT_SYMBOL_GPL(counter_signal_read_value_set);
/**
* counter_count_read_value_set - set counter_count_read_value data
* @val: counter_count_read_value structure to set
* @type: property Count data represents
* @data: Count data
*
* This function sets an opaque counter_count_read_value structure with the
* provided Count data.
*/
void counter_count_read_value_set(struct counter_count_read_value *const val,
const enum counter_count_value_type type,
void *const data)
{
switch (type) {
case COUNTER_COUNT_POSITION:
val->len = sprintf(val->buf, "%lu\n", *(unsigned long *)data);
break;
default:
val->len = 0;
}
}
EXPORT_SYMBOL_GPL(counter_count_read_value_set);
/**
* counter_count_write_value_get - get counter_count_write_value data
* @data: Count data
* @type: property Count data represents
* @val: counter_count_write_value structure containing data
*
* This function extracts Count data from the provided opaque
* counter_count_write_value structure and stores it at the address provided by
* @data.
*
* RETURNS:
* 0 on success, negative error number on failure.
*/
int counter_count_write_value_get(void *const data,
const enum counter_count_value_type type,
const struct counter_count_write_value *const val)
{
int err;
switch (type) {
case COUNTER_COUNT_POSITION:
err = kstrtoul(val->buf, 0, data);
if (err)
return err;
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(counter_count_write_value_get);
struct counter_attr_parm {
struct counter_device_attr_group *group;
const char *prefix;
@ -369,6 +289,11 @@ struct counter_signal_unit {
struct counter_signal *signal;
};
static const char *const counter_signal_value_str[] = {
[COUNTER_SIGNAL_LOW] = "low",
[COUNTER_SIGNAL_HIGH] = "high"
};
static ssize_t counter_signal_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -377,13 +302,13 @@ static ssize_t counter_signal_show(struct device *dev,
const struct counter_signal_unit *const component = devattr->component;
struct counter_signal *const signal = component->signal;
int err;
struct counter_signal_read_value val = { .buf = buf };
enum counter_signal_value val;
err = counter->ops->signal_read(counter, signal, &val);
if (err)
return err;
return val.len;
return sprintf(buf, "%s\n", counter_signal_value_str[val]);
}
struct counter_name_unit {
@ -788,13 +713,13 @@ static ssize_t counter_count_show(struct device *dev,
const struct counter_count_unit *const component = devattr->component;
struct counter_count *const count = component->count;
int err;
struct counter_count_read_value val = { .buf = buf };
unsigned long val;
err = counter->ops->count_read(counter, count, &val);
if (err)
return err;
return val.len;
return sprintf(buf, "%lu\n", val);
}
static ssize_t counter_count_store(struct device *dev,
@ -806,9 +731,13 @@ static ssize_t counter_count_store(struct device *dev,
const struct counter_count_unit *const component = devattr->component;
struct counter_count *const count = component->count;
int err;
struct counter_count_write_value val = { .buf = buf };
unsigned long val;
err = counter->ops->count_write(counter, count, &val);
err = kstrtoul(buf, 0, &val);
if (err)
return err;
err = counter->ops->count_write(counter, count, val);
if (err)
return err;

View File

@ -178,31 +178,25 @@ static const enum counter_count_function ftm_quaddec_count_functions[] = {
static int ftm_quaddec_count_read(struct counter_device *counter,
struct counter_count *count,
struct counter_count_read_value *val)
unsigned long *val)
{
struct ftm_quaddec *const ftm = counter->priv;
uint32_t cntval;
ftm_read(ftm, FTM_CNT, &cntval);
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cntval);
*val = cntval;
return 0;
}
static int ftm_quaddec_count_write(struct counter_device *counter,
struct counter_count *count,
struct counter_count_write_value *val)
const unsigned long val)
{
struct ftm_quaddec *const ftm = counter->priv;
u32 cnt;
int err;
err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
if (err)
return err;
if (cnt != 0) {
if (val != 0) {
dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n");
return -EINVAL;
}

View File

@ -347,7 +347,7 @@ static const struct iio_chan_spec stm32_lptim_cnt_channels = {
};
/**
* stm32_lptim_cnt_function - enumerates stm32 LPTimer counter & encoder modes
* enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes
* @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges
* @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature)
*/
@ -377,8 +377,7 @@ static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
};
static int stm32_lptim_cnt_read(struct counter_device *counter,
struct counter_count *count,
struct counter_count_read_value *val)
struct counter_count *count, unsigned long *val)
{
struct stm32_lptim_cnt *const priv = counter->priv;
u32 cnt;
@ -388,7 +387,7 @@ static int stm32_lptim_cnt_read(struct counter_device *counter,
if (ret)
return ret;
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt);
*val = cnt;
return 0;
}

View File

@ -28,7 +28,7 @@ struct stm32_timer_cnt {
};
/**
* stm32_count_function - enumerates stm32 timer counter encoder modes
* enum stm32_count_function - enumerates stm32 timer counter encoder modes
* @STM32_COUNT_SLAVE_MODE_DISABLED: counts on internal clock when CEN=1
* @STM32_COUNT_ENCODER_MODE_1: counts TI1FP1 edges, depending on TI2FP2 level
* @STM32_COUNT_ENCODER_MODE_2: counts TI2FP2 edges, depending on TI1FP1 level
@ -48,34 +48,27 @@ static enum counter_count_function stm32_count_functions[] = {
};
static int stm32_count_read(struct counter_device *counter,
struct counter_count *count,
struct counter_count_read_value *val)
struct counter_count *count, unsigned long *val)
{
struct stm32_timer_cnt *const priv = counter->priv;
u32 cnt;
regmap_read(priv->regmap, TIM_CNT, &cnt);
counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt);
*val = cnt;
return 0;
}
static int stm32_count_write(struct counter_device *counter,
struct counter_count *count,
struct counter_count_write_value *val)
const unsigned long val)
{
struct stm32_timer_cnt *const priv = counter->priv;
u32 cnt;
int err;
err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val);
if (err)
return err;
if (cnt > priv->ceiling)
if (val > priv->ceiling)
return -EINVAL;
return regmap_write(priv->regmap, TIM_CNT, cnt);
return regmap_write(priv->regmap, TIM_CNT, val);
}
static int stm32_count_function_get(struct counter_device *counter,
@ -219,8 +212,8 @@ static ssize_t stm32_count_enable_write(struct counter_device *counter,
if (enable) {
regmap_read(priv->regmap, TIM_CR1, &cr1);
if (!(cr1 & TIM_CR1_CEN))
clk_enable(priv->clk);
if (!(cr1 & TIM_CR1_CEN))
clk_enable(priv->clk);
regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
TIM_CR1_CEN);

466
drivers/counter/ti-eqep.c Normal file
View File

@ -0,0 +1,466 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2019 David Lechner <david@lechnology.com>
*
* Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP)
*/
#include <linux/bitops.h>
#include <linux/counter.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
/* 32-bit registers */
#define QPOSCNT 0x0
#define QPOSINIT 0x4
#define QPOSMAX 0x8
#define QPOSCMP 0xc
#define QPOSILAT 0x10
#define QPOSSLAT 0x14
#define QPOSLAT 0x18
#define QUTMR 0x1c
#define QUPRD 0x20
/* 16-bit registers */
#define QWDTMR 0x0 /* 0x24 */
#define QWDPRD 0x2 /* 0x26 */
#define QDECCTL 0x4 /* 0x28 */
#define QEPCTL 0x6 /* 0x2a */
#define QCAPCTL 0x8 /* 0x2c */
#define QPOSCTL 0xa /* 0x2e */
#define QEINT 0xc /* 0x30 */
#define QFLG 0xe /* 0x32 */
#define QCLR 0x10 /* 0x34 */
#define QFRC 0x12 /* 0x36 */
#define QEPSTS 0x14 /* 0x38 */
#define QCTMR 0x16 /* 0x3a */
#define QCPRD 0x18 /* 0x3c */
#define QCTMRLAT 0x1a /* 0x3e */
#define QCPRDLAT 0x1c /* 0x40 */
#define QDECCTL_QSRC_SHIFT 14
#define QDECCTL_QSRC GENMASK(15, 14)
#define QDECCTL_SOEN BIT(13)
#define QDECCTL_SPSEL BIT(12)
#define QDECCTL_XCR BIT(11)
#define QDECCTL_SWAP BIT(10)
#define QDECCTL_IGATE BIT(9)
#define QDECCTL_QAP BIT(8)
#define QDECCTL_QBP BIT(7)
#define QDECCTL_QIP BIT(6)
#define QDECCTL_QSP BIT(5)
#define QEPCTL_FREE_SOFT GENMASK(15, 14)
#define QEPCTL_PCRM GENMASK(13, 12)
#define QEPCTL_SEI GENMASK(11, 10)
#define QEPCTL_IEI GENMASK(9, 8)
#define QEPCTL_SWI BIT(7)
#define QEPCTL_SEL BIT(6)
#define QEPCTL_IEL GENMASK(5, 4)
#define QEPCTL_PHEN BIT(3)
#define QEPCTL_QCLM BIT(2)
#define QEPCTL_UTE BIT(1)
#define QEPCTL_WDE BIT(0)
/* EQEP Inputs */
enum {
TI_EQEP_SIGNAL_QEPA, /* QEPA/XCLK */
TI_EQEP_SIGNAL_QEPB, /* QEPB/XDIR */
};
/* Position Counter Input Modes */
enum {
TI_EQEP_COUNT_FUNC_QUAD_COUNT,
TI_EQEP_COUNT_FUNC_DIR_COUNT,
TI_EQEP_COUNT_FUNC_UP_COUNT,
TI_EQEP_COUNT_FUNC_DOWN_COUNT,
};
enum {
TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES,
TI_EQEP_SYNAPSE_ACTION_RISING_EDGE,
TI_EQEP_SYNAPSE_ACTION_NONE,
};
struct ti_eqep_cnt {
struct counter_device counter;
struct regmap *regmap32;
struct regmap *regmap16;
};
static int ti_eqep_count_read(struct counter_device *counter,
struct counter_count *count, unsigned long *val)
{
struct ti_eqep_cnt *priv = counter->priv;
u32 cnt;
regmap_read(priv->regmap32, QPOSCNT, &cnt);
*val = cnt;
return 0;
}
static int ti_eqep_count_write(struct counter_device *counter,
struct counter_count *count, unsigned long val)
{
struct ti_eqep_cnt *priv = counter->priv;
u32 max;
regmap_read(priv->regmap32, QPOSMAX, &max);
if (val > max)
return -EINVAL;
return regmap_write(priv->regmap32, QPOSCNT, val);
}
static int ti_eqep_function_get(struct counter_device *counter,
struct counter_count *count, size_t *function)
{
struct ti_eqep_cnt *priv = counter->priv;
u32 qdecctl;
regmap_read(priv->regmap16, QDECCTL, &qdecctl);
*function = (qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT;
return 0;
}
static int ti_eqep_function_set(struct counter_device *counter,
struct counter_count *count, size_t function)
{
struct ti_eqep_cnt *priv = counter->priv;
return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC,
function << QDECCTL_QSRC_SHIFT);
}
static int ti_eqep_action_get(struct counter_device *counter,
struct counter_count *count,
struct counter_synapse *synapse, size_t *action)
{
struct ti_eqep_cnt *priv = counter->priv;
size_t function;
u32 qdecctl;
int err;
err = ti_eqep_function_get(counter, count, &function);
if (err)
return err;
switch (function) {
case TI_EQEP_COUNT_FUNC_QUAD_COUNT:
/* In quadrature mode, the rising and falling edge of both
* QEPA and QEPB trigger QCLK.
*/
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
break;
case TI_EQEP_COUNT_FUNC_DIR_COUNT:
/* In direction-count mode only rising edge of QEPA is counted
* and QEPB gives direction.
*/
switch (synapse->signal->id) {
case TI_EQEP_SIGNAL_QEPA:
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
break;
default:
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
break;
}
break;
case TI_EQEP_COUNT_FUNC_UP_COUNT:
case TI_EQEP_COUNT_FUNC_DOWN_COUNT:
/* In up/down-count modes only QEPA is counted and QEPB is not
* used.
*/
switch (synapse->signal->id) {
case TI_EQEP_SIGNAL_QEPA:
err = regmap_read(priv->regmap16, QDECCTL, &qdecctl);
if (err)
return err;
if (qdecctl & QDECCTL_XCR)
*action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES;
else
*action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE;
break;
default:
*action = TI_EQEP_SYNAPSE_ACTION_NONE;
break;
}
break;
}
return 0;
}
static const struct counter_ops ti_eqep_counter_ops = {
.count_read = ti_eqep_count_read,
.count_write = ti_eqep_count_write,
.function_get = ti_eqep_function_get,
.function_set = ti_eqep_function_set,
.action_get = ti_eqep_action_get,
};
static ssize_t ti_eqep_position_ceiling_read(struct counter_device *counter,
struct counter_count *count,
void *ext_priv, char *buf)
{
struct ti_eqep_cnt *priv = counter->priv;
u32 qposmax;
regmap_read(priv->regmap32, QPOSMAX, &qposmax);
return sprintf(buf, "%u\n", qposmax);
}
static ssize_t ti_eqep_position_ceiling_write(struct counter_device *counter,
struct counter_count *count,
void *ext_priv, const char *buf,
size_t len)
{
struct ti_eqep_cnt *priv = counter->priv;
int err;
u32 res;
err = kstrtouint(buf, 0, &res);
if (err < 0)
return err;
regmap_write(priv->regmap32, QPOSMAX, res);
return len;
}
static ssize_t ti_eqep_position_floor_read(struct counter_device *counter,
struct counter_count *count,
void *ext_priv, char *buf)
{
struct ti_eqep_cnt *priv = counter->priv;
u32 qposinit;
regmap_read(priv->regmap32, QPOSINIT, &qposinit);
return sprintf(buf, "%u\n", qposinit);
}
static ssize_t ti_eqep_position_floor_write(struct counter_device *counter,
struct counter_count *count,
void *ext_priv, const char *buf,
size_t len)
{
struct ti_eqep_cnt *priv = counter->priv;
int err;
u32 res;
err = kstrtouint(buf, 0, &res);
if (err < 0)
return err;
regmap_write(priv->regmap32, QPOSINIT, res);
return len;
}
static ssize_t ti_eqep_position_enable_read(struct counter_device *counter,
struct counter_count *count,
void *ext_priv, char *buf)
{
struct ti_eqep_cnt *priv = counter->priv;
u32 qepctl;
regmap_read(priv->regmap16, QEPCTL, &qepctl);
return sprintf(buf, "%u\n", !!(qepctl & QEPCTL_PHEN));
}
static ssize_t ti_eqep_position_enable_write(struct counter_device *counter,
struct counter_count *count,
void *ext_priv, const char *buf,
size_t len)
{
struct ti_eqep_cnt *priv = counter->priv;
int err;
bool res;
err = kstrtobool(buf, &res);
if (err < 0)
return err;
regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, res ? -1 : 0);
return len;
}
static struct counter_count_ext ti_eqep_position_ext[] = {
{
.name = "ceiling",
.read = ti_eqep_position_ceiling_read,
.write = ti_eqep_position_ceiling_write,
},
{
.name = "floor",
.read = ti_eqep_position_floor_read,
.write = ti_eqep_position_floor_write,
},
{
.name = "enable",
.read = ti_eqep_position_enable_read,
.write = ti_eqep_position_enable_write,
},
};
static struct counter_signal ti_eqep_signals[] = {
[TI_EQEP_SIGNAL_QEPA] = {
.id = TI_EQEP_SIGNAL_QEPA,
.name = "QEPA"
},
[TI_EQEP_SIGNAL_QEPB] = {
.id = TI_EQEP_SIGNAL_QEPB,
.name = "QEPB"
},
};
static const enum counter_count_function ti_eqep_position_functions[] = {
[TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
[TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
[TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_COUNT_FUNCTION_INCREASE,
[TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_COUNT_FUNCTION_DECREASE,
};
static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = {
[TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
[TI_EQEP_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
[TI_EQEP_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
};
static struct counter_synapse ti_eqep_position_synapses[] = {
{
.actions_list = ti_eqep_position_synapse_actions,
.num_actions = ARRAY_SIZE(ti_eqep_position_synapse_actions),
.signal = &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA],
},
{
.actions_list = ti_eqep_position_synapse_actions,
.num_actions = ARRAY_SIZE(ti_eqep_position_synapse_actions),
.signal = &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB],
},
};
static struct counter_count ti_eqep_counts[] = {
{
.id = 0,
.name = "QPOSCNT",
.functions_list = ti_eqep_position_functions,
.num_functions = ARRAY_SIZE(ti_eqep_position_functions),
.synapses = ti_eqep_position_synapses,
.num_synapses = ARRAY_SIZE(ti_eqep_position_synapses),
.ext = ti_eqep_position_ext,
.num_ext = ARRAY_SIZE(ti_eqep_position_ext),
},
};
static const struct regmap_config ti_eqep_regmap32_config = {
.name = "32-bit",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x24,
};
static const struct regmap_config ti_eqep_regmap16_config = {
.name = "16-bit",
.reg_bits = 16,
.val_bits = 16,
.reg_stride = 2,
.max_register = 0x1e,
};
static int ti_eqep_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ti_eqep_cnt *priv;
void __iomem *base;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
priv->regmap32 = devm_regmap_init_mmio(dev, base,
&ti_eqep_regmap32_config);
if (IS_ERR(priv->regmap32))
return PTR_ERR(priv->regmap32);
priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24,
&ti_eqep_regmap16_config);
if (IS_ERR(priv->regmap16))
return PTR_ERR(priv->regmap16);
priv->counter.name = dev_name(dev);
priv->counter.parent = dev;
priv->counter.ops = &ti_eqep_counter_ops;
priv->counter.counts = ti_eqep_counts;
priv->counter.num_counts = ARRAY_SIZE(ti_eqep_counts);
priv->counter.signals = ti_eqep_signals;
priv->counter.num_signals = ARRAY_SIZE(ti_eqep_signals);
priv->counter.priv = priv;
platform_set_drvdata(pdev, priv);
/*
* Need to make sure power is turned on. On AM33xx, this comes from the
* parent PWMSS bus driver. On AM17xx, this comes from the PSC power
* domain.
*/
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
err = counter_register(&priv->counter);
if (err < 0) {
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return err;
}
return 0;
}
static int ti_eqep_remove(struct platform_device *pdev)
{
struct ti_eqep_cnt *priv = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
counter_unregister(&priv->counter);
pm_runtime_put_sync(dev),
pm_runtime_disable(dev);
return 0;
}
static const struct of_device_id ti_eqep_of_match[] = {
{ .compatible = "ti,am3352-eqep", },
{ },
};
MODULE_DEVICE_TABLE(of, ti_eqep_of_match);
static struct platform_driver ti_eqep_driver = {
.probe = ti_eqep_probe,
.remove = ti_eqep_remove,
.driver = {
.name = "ti-eqep-cnt",
.of_match_table = ti_eqep_of_match,
},
};
module_platform_driver(ti_eqep_driver);
MODULE_AUTHOR("David Lechner <david@lechnology.com>");
MODULE_DESCRIPTION("TI eQEP counter driver");
MODULE_LICENSE("GPL v2");

View File

@ -15,7 +15,6 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>

View File

@ -55,6 +55,16 @@ config AD7291
To compile this driver as a module, choose M here: the
module will be called ad7291.
config AD7292
tristate "Analog Devices AD7292 ADC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD7292
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7292.
config AD7298
tristate "Analog Devices AD7298 ADC driver"
depends on SPI
@ -442,6 +452,17 @@ config INGENIC_ADC
This driver can also be built as a module. If so, the module will be
called ingenic_adc.
config INTEL_MRFLD_ADC
tristate "Intel Merrifield Basin Cove ADC driver"
depends on INTEL_SOC_PMIC_MRFLD
help
Say yes here to have support for Basin Cove power management IC (PMIC) ADC
device. Depending on platform configuration, this general purpose ADC can
be used for sampling sensors such as thermal resistors.
To compile this driver as a module, choose M here: the module will be
called intel_mrfld_adc.
config IMX7D_ADC
tristate "Freescale IMX7D ADC driver"
depends on ARCH_MXC || COMPILE_TEST
@ -518,8 +539,8 @@ config MAX1027
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Maxim SPI ADC models
max1027, max1029 and max1031.
Say yes here to build support for Maxim SPI {10,12}-bit ADC models:
max1027, max1029, max1031, max1227, max1229 and max1231.
To compile this driver as a module, choose M here: the module will be
called max1027.

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o
@ -43,6 +44,7 @@ obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o

350
drivers/iio/adc/ad7292.c Normal file
View File

@ -0,0 +1,350 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices AD7292 SPI ADC driver
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#define ADI_VENDOR_ID 0x0018
/* AD7292 registers definition */
#define AD7292_REG_VENDOR_ID 0x00
#define AD7292_REG_CONF_BANK 0x05
#define AD7292_REG_CONV_COMM 0x0E
#define AD7292_REG_ADC_CH(x) (0x10 + (x))
/* AD7292 configuration bank subregisters definition */
#define AD7292_BANK_REG_VIN_RNG0 0x10
#define AD7292_BANK_REG_VIN_RNG1 0x11
#define AD7292_BANK_REG_SAMP_MODE 0x12
#define AD7292_RD_FLAG_MSK(x) (BIT(7) | ((x) & 0x3F))
/* AD7292_REG_ADC_CONVERSION */
#define AD7292_ADC_DATA_MASK GENMASK(15, 6)
#define AD7292_ADC_DATA(x) FIELD_GET(AD7292_ADC_DATA_MASK, x)
/* AD7292_CHANNEL_SAMPLING_MODE */
#define AD7292_CH_SAMP_MODE(reg, ch) (((reg) >> 8) & BIT(ch))
/* AD7292_CHANNEL_VIN_RANGE */
#define AD7292_CH_VIN_RANGE(reg, ch) ((reg) & BIT(ch))
#define AD7292_VOLTAGE_CHAN(_chan) \
{ \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
.channel = _chan, \
}
static const struct iio_chan_spec ad7292_channels[] = {
AD7292_VOLTAGE_CHAN(0),
AD7292_VOLTAGE_CHAN(1),
AD7292_VOLTAGE_CHAN(2),
AD7292_VOLTAGE_CHAN(3),
AD7292_VOLTAGE_CHAN(4),
AD7292_VOLTAGE_CHAN(5),
AD7292_VOLTAGE_CHAN(6),
AD7292_VOLTAGE_CHAN(7)
};
static const struct iio_chan_spec ad7292_channels_diff[] = {
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.indexed = 1,
.differential = 1,
.channel = 0,
.channel2 = 1,
},
AD7292_VOLTAGE_CHAN(2),
AD7292_VOLTAGE_CHAN(3),
AD7292_VOLTAGE_CHAN(4),
AD7292_VOLTAGE_CHAN(5),
AD7292_VOLTAGE_CHAN(6),
AD7292_VOLTAGE_CHAN(7)
};
struct ad7292_state {
struct spi_device *spi;
struct regulator *reg;
unsigned short vref_mv;
__be16 d16 ____cacheline_aligned;
u8 d8[2];
};
static int ad7292_spi_reg_read(struct ad7292_state *st, unsigned int addr)
{
int ret;
st->d8[0] = AD7292_RD_FLAG_MSK(addr);
ret = spi_write_then_read(st->spi, st->d8, 1, &st->d16, 2);
if (ret < 0)
return ret;
return be16_to_cpu(st->d16);
}
static int ad7292_spi_subreg_read(struct ad7292_state *st, unsigned int addr,
unsigned int sub_addr, unsigned int len)
{
unsigned int shift = 16 - (8 * len);
int ret;
st->d8[0] = AD7292_RD_FLAG_MSK(addr);
st->d8[1] = sub_addr;
ret = spi_write_then_read(st->spi, st->d8, 2, &st->d16, len);
if (ret < 0)
return ret;
return (be16_to_cpu(st->d16) >> shift);
}
static int ad7292_single_conversion(struct ad7292_state *st,
unsigned int chan_addr)
{
int ret;
struct spi_transfer t[] = {
{
.tx_buf = &st->d8,
.len = 4,
.delay_usecs = 6,
}, {
.rx_buf = &st->d16,
.len = 2,
},
};
st->d8[0] = chan_addr;
st->d8[1] = AD7292_RD_FLAG_MSK(AD7292_REG_CONV_COMM);
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
return ret;
return be16_to_cpu(st->d16);
}
static int ad7292_vin_range_multiplier(struct ad7292_state *st, int channel)
{
int samp_mode, range0, range1, factor = 1;
/*
* Every AD7292 ADC channel may have its input range adjusted according
* to the settings at the ADC sampling mode and VIN range subregisters.
* For a given channel, the minimum input range is equal to Vref, and it
* may be increased by a multiplier factor of 2 or 4 according to the
* following rule:
* If channel is being sampled with respect to AGND:
* factor = 4 if VIN range0 and VIN range1 equal 0
* factor = 2 if only one of VIN ranges equal 1
* factor = 1 if both VIN range0 and VIN range1 equal 1
* If channel is being sampled with respect to AVDD:
* factor = 4 if VIN range0 and VIN range1 equal 0
* Behavior is undefined if any of VIN range doesn't equal 0
*/
samp_mode = ad7292_spi_subreg_read(st, AD7292_REG_CONF_BANK,
AD7292_BANK_REG_SAMP_MODE, 2);
if (samp_mode < 0)
return samp_mode;
range0 = ad7292_spi_subreg_read(st, AD7292_REG_CONF_BANK,
AD7292_BANK_REG_VIN_RNG0, 2);
if (range0 < 0)
return range0;
range1 = ad7292_spi_subreg_read(st, AD7292_REG_CONF_BANK,
AD7292_BANK_REG_VIN_RNG1, 2);
if (range1 < 0)
return range1;
if (AD7292_CH_SAMP_MODE(samp_mode, channel)) {
/* Sampling with respect to AGND */
if (!AD7292_CH_VIN_RANGE(range0, channel))
factor *= 2;
if (!AD7292_CH_VIN_RANGE(range1, channel))
factor *= 2;
} else {
/* Sampling with respect to AVDD */
if (AD7292_CH_VIN_RANGE(range0, channel) ||
AD7292_CH_VIN_RANGE(range1, channel))
return -EPERM;
factor = 4;
}
return factor;
}
static int ad7292_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long info)
{
struct ad7292_state *st = iio_priv(indio_dev);
unsigned int ch_addr;
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
ch_addr = AD7292_REG_ADC_CH(chan->channel);
ret = ad7292_single_conversion(st, ch_addr);
if (ret < 0)
return ret;
*val = AD7292_ADC_DATA(ret);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/*
* To convert a raw value to standard units, the IIO defines
* this formula: Scaled value = (raw + offset) * scale.
* For the scale to be a correct multiplier for (raw + offset),
* it must be calculated as the input range divided by the
* number of possible distinct input values. Given the ADC data
* is 10 bit long, it may assume 2^10 distinct values.
* Hence, scale = range / 2^10. The IIO_VAL_FRACTIONAL_LOG2
* return type indicates to the IIO API to divide *val by 2 to
* the power of *val2 when returning from read_raw.
*/
ret = ad7292_vin_range_multiplier(st, chan->channel);
if (ret < 0)
return ret;
*val = st->vref_mv * ret;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
default:
break;
}
return -EINVAL;
}
static const struct iio_info ad7292_info = {
.read_raw = ad7292_read_raw,
};
static void ad7292_regulator_disable(void *data)
{
struct ad7292_state *st = data;
regulator_disable(st->reg);
}
static int ad7292_probe(struct spi_device *spi)
{
struct ad7292_state *st;
struct iio_dev *indio_dev;
struct device_node *child;
bool diff_channels = 0;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
st->spi = spi;
ret = ad7292_spi_reg_read(st, AD7292_REG_VENDOR_ID);
if (ret != ADI_VENDOR_ID) {
dev_err(&spi->dev, "Wrong vendor id 0x%x\n", ret);
return -EINVAL;
}
spi_set_drvdata(spi, indio_dev);
st->reg = devm_regulator_get_optional(&spi->dev, "vref");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);
if (ret) {
dev_err(&spi->dev,
"Failed to enable external vref supply\n");
return ret;
}
ret = devm_add_action_or_reset(&spi->dev,
ad7292_regulator_disable, st);
if (ret) {
regulator_disable(st->reg);
return ret;
}
ret = regulator_get_voltage(st->reg);
if (ret < 0)
return ret;
st->vref_mv = ret / 1000;
} else {
/* Use the internal voltage reference. */
st->vref_mv = 1250;
}
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ad7292_info;
for_each_available_child_of_node(spi->dev.of_node, child) {
diff_channels = of_property_read_bool(child, "diff-channels");
if (diff_channels)
break;
}
if (diff_channels) {
indio_dev->num_channels = ARRAY_SIZE(ad7292_channels_diff);
indio_dev->channels = ad7292_channels_diff;
} else {
indio_dev->num_channels = ARRAY_SIZE(ad7292_channels);
indio_dev->channels = ad7292_channels;
}
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad7292_id_table[] = {
{ "ad7292", 0 },
{}
};
MODULE_DEVICE_TABLE(spi, ad7292_id_table);
static const struct of_device_id ad7292_of_match[] = {
{ .compatible = "adi,ad7292" },
{ },
};
MODULE_DEVICE_TABLE(of, ad7292_of_match);
static struct spi_driver ad7292_driver = {
.driver = {
.name = "ad7292",
.of_match_table = ad7292_of_match,
},
.probe = ad7292_probe,
.id_table = ad7292_id_table,
};
module_spi_driver(ad7292_driver);
MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt1@gmail.com>");
MODULE_DESCRIPTION("Analog Devices AD7292 ADC driver");
MODULE_LICENSE("GPL v2");

View File

@ -54,38 +54,20 @@ struct ad7949_adc_chip {
u8 resolution;
u16 cfg;
unsigned int current_channel;
u32 buffer ____cacheline_aligned;
u16 buffer ____cacheline_aligned;
};
static bool ad7949_spi_cfg_is_read_back(struct ad7949_adc_chip *ad7949_adc)
{
if (!(ad7949_adc->cfg & AD7949_CFG_READ_BACK))
return true;
return false;
}
static int ad7949_spi_bits_per_word(struct ad7949_adc_chip *ad7949_adc)
{
int ret = ad7949_adc->resolution;
if (ad7949_spi_cfg_is_read_back(ad7949_adc))
ret += AD7949_CFG_REG_SIZE_BITS;
return ret;
}
static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
u16 mask)
{
int ret;
int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
int bits_per_word = ad7949_adc->resolution;
int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
struct spi_message msg;
struct spi_transfer tx[] = {
{
.tx_buf = &ad7949_adc->buffer,
.len = 4,
.len = 2,
.bits_per_word = bits_per_word,
},
};
@ -107,13 +89,13 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
unsigned int channel)
{
int ret;
int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
int bits_per_word = ad7949_adc->resolution;
int mask = GENMASK(ad7949_adc->resolution, 0);
struct spi_message msg;
struct spi_transfer tx[] = {
{
.rx_buf = &ad7949_adc->buffer,
.len = 4,
.len = 2,
.bits_per_word = bits_per_word,
},
};
@ -138,10 +120,7 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
ad7949_adc->current_channel = channel;
if (ad7949_spi_cfg_is_read_back(ad7949_adc))
*val = (ad7949_adc->buffer >> AD7949_CFG_REG_SIZE_BITS) & mask;
else
*val = ad7949_adc->buffer & mask;
*val = ad7949_adc->buffer & mask;
return 0;
}

View File

@ -205,7 +205,7 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta,
}
EXPORT_SYMBOL_GPL(ad_sd_reset);
static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
unsigned int mode, unsigned int channel)
{
int ret;
@ -242,6 +242,7 @@ out:
return ret;
}
EXPORT_SYMBOL_GPL(ad_sd_calibrate);
/**
* ad_sd_calibrate_all() - Performs channel calibration

View File

@ -173,7 +173,6 @@ static int aspeed_adc_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct aspeed_adc_data *data;
const struct aspeed_adc_model_data *model_data;
struct resource *res;
const char *clk_parent_name;
int ret;
u32 adc_engine_control_reg_val;
@ -185,8 +184,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
data = iio_priv(indio_dev);
data->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_ioremap_resource(&pdev->dev, res);
data->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->base))
return PTR_ERR(data->base);

View File

@ -1483,7 +1483,7 @@ dma_free_area:
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
dma_chan_disable:
dma_release_channel(st->dma_st.dma_chan);
st->dma_st.dma_chan = 0;
st->dma_st.dma_chan = NULL;
dma_exit:
dev_info(&pdev->dev, "continuing without DMA support\n");
}
@ -1506,7 +1506,7 @@ static void at91_adc_dma_disable(struct platform_device *pdev)
dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE,
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
dma_release_channel(st->dma_st.dma_chan);
st->dma_st.dma_chan = 0;
st->dma_st.dma_chan = NULL;
dev_info(&pdev->dev, "continuing without DMA support\n");
}

View File

@ -308,7 +308,7 @@ static int iproc_adc_do_read(struct iio_dev *indio_dev,
"IntMask set failed. Read will likely fail.");
read_len = -EIO;
goto adc_err;
};
}
}
regmap_read(adc_priv->regmap, IPROC_INTERRUPT_MASK, &val_check);

View File

@ -310,7 +310,6 @@ static int cc10001_adc_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
struct cc10001_adc_device *adc_dev;
unsigned long adc_clk_rate;
struct resource *res;
struct iio_dev *indio_dev;
unsigned long channel_map;
int ret;
@ -340,8 +339,7 @@ static int cc10001_adc_probe(struct platform_device *pdev)
indio_dev->info = &cc10001_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adc_dev->reg_base)) {
ret = PTR_ERR(adc_dev->reg_base);
goto err_disable_reg;

View File

@ -1008,7 +1008,7 @@ static int cpcap_adc_probe(struct platform_device *pdev)
error = devm_request_threaded_irq(&pdev->dev, ddata->irq, NULL,
cpcap_adc_irq_thread,
IRQF_TRIGGER_NONE,
IRQF_TRIGGER_NONE | IRQF_ONESHOT,
"cpcap-adc", indio_dev);
if (error) {
dev_err(&pdev->dev, "could not get irq: %i\n",

View File

@ -524,6 +524,10 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
u16 conflict;
unsigned int trigger_chan;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret)
return ret;
mutex_lock(&dln2->mutex);
/* Enable ADC */
@ -537,6 +541,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
(int)conflict);
ret = -EBUSY;
}
iio_triggered_buffer_predisable(indio_dev);
return ret;
}
@ -550,6 +555,7 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
mutex_unlock(&dln2->mutex);
if (ret < 0) {
dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
iio_triggered_buffer_predisable(indio_dev);
return ret;
}
} else {
@ -557,12 +563,12 @@ static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
mutex_unlock(&dln2->mutex);
}
return iio_triggered_buffer_postenable(indio_dev);
return 0;
}
static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
{
int ret;
int ret, ret2;
struct dln2_adc *dln2 = iio_priv(indio_dev);
mutex_lock(&dln2->mutex);
@ -577,12 +583,14 @@ static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
ret = dln2_adc_set_port_enabled(dln2, false, NULL);
mutex_unlock(&dln2->mutex);
if (ret < 0) {
if (ret < 0)
dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
return ret;
}
return iio_triggered_buffer_predisable(indio_dev);
ret2 = iio_triggered_buffer_predisable(indio_dev);
if (ret == 0)
ret = ret2;
return ret;
}
static const struct iio_buffer_setup_ops dln2_adc_buffer_setup_ops = {

View File

@ -651,7 +651,7 @@ static irqreturn_t exynos_ts_isr(int irq, void *dev_id)
input_sync(info->input);
usleep_range(1000, 1100);
};
}
writel(0, ADC_V1_CLRINTPNDNUP(info->regs));
@ -769,7 +769,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev);
struct iio_dev *indio_dev = NULL;
struct resource *mem;
bool has_ts = false;
int ret = -ENODEV;
int irq;
@ -788,8 +787,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
return -EINVAL;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);

View File

@ -23,6 +23,7 @@
/* gain to pulse and scale conversion */
#define HX711_GAIN_MAX 3
#define HX711_RESET_GAIN 128
struct hx711_gain_to_scale {
int gain;
@ -185,8 +186,7 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data)
static int hx711_reset(struct hx711_data *hx711_data)
{
int ret;
int val = gpiod_get_value(hx711_data->gpiod_dout);
int val = hx711_wait_for_ready(hx711_data);
if (val) {
/*
@ -202,22 +202,10 @@ static int hx711_reset(struct hx711_data *hx711_data)
msleep(10);
gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
ret = hx711_wait_for_ready(hx711_data);
if (ret)
return ret;
/*
* after a reset the gain is 128 so we do a dummy read
* to set the gain for the next read
*/
ret = hx711_read(hx711_data);
if (ret < 0)
return ret;
/*
* after a dummy read we need to wait vor readiness
* for not mixing gain pulses with the clock
*/
val = hx711_wait_for_ready(hx711_data);
/* after a reset the gain is 128 */
hx711_data->gain_set = HX711_RESET_GAIN;
}
return val;

View File

@ -25,9 +25,13 @@
#define JZ_ADC_REG_ADSDAT 0x20
#define JZ_ADC_REG_ADCLK 0x28
#define JZ_ADC_REG_ENABLE_PD BIT(7)
#define JZ_ADC_REG_CFG_AUX_MD (BIT(0) | BIT(1))
#define JZ_ADC_REG_CFG_BAT_MD BIT(4)
#define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0
#define JZ_ADC_REG_ADCLK_CLKDIV10US_LSB 16
#define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16
#define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB 8
#define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB 16
#define JZ_ADC_AUX_VREF 3300
#define JZ_ADC_AUX_VREF_BITS 12
@ -37,6 +41,8 @@
#define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
#define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
#define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
#define JZ4770_ADC_BATTERY_VREF 6600
#define JZ4770_ADC_BATTERY_VREF_BITS 12
struct ingenic_adc;
@ -47,6 +53,8 @@ struct ingenic_adc_soc_data {
size_t battery_raw_avail_size;
const int *battery_scale_avail;
size_t battery_scale_avail_size;
unsigned int battery_vref_mode: 1;
unsigned int has_aux2: 1;
int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
};
@ -54,6 +62,7 @@ struct ingenic_adc {
void __iomem *base;
struct clk *clk;
struct mutex lock;
struct mutex aux_lock;
const struct ingenic_adc_soc_data *soc_data;
bool low_vref_mode;
};
@ -120,6 +129,8 @@ static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case INGENIC_ADC_BATTERY:
if (!adc->soc_data->battery_vref_mode)
return -EINVAL;
if (val > JZ_ADC_BATTERY_LOW_VREF) {
ingenic_adc_set_config(adc,
JZ_ADC_REG_CFG_BAT_MD,
@ -158,6 +169,14 @@ static const int jz4740_adc_battery_scale_avail[] = {
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
};
static const int jz4770_adc_battery_raw_avail[] = {
0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
};
static const int jz4770_adc_battery_scale_avail[] = {
JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
};
static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
{
struct clk *parent_clk;
@ -187,7 +206,45 @@ static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
/* We also need a divider that produces a 10us clock. */
div_10us = DIV_ROUND_UP(rate, 100000);
writel(((div_10us - 1) << JZ_ADC_REG_ADCLK_CLKDIV10US_LSB) |
writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) |
(div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
adc->base + JZ_ADC_REG_ADCLK);
return 0;
}
static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
{
struct clk *parent_clk;
unsigned long parent_rate, rate;
unsigned int div_main, div_ms, div_10us;
parent_clk = clk_get_parent(adc->clk);
if (!parent_clk) {
dev_err(dev, "ADC clock has no parent\n");
return -ENODEV;
}
parent_rate = clk_get_rate(parent_clk);
/*
* The JZ4770 ADC works at 20 kHz to 200 kHz.
* We pick the highest rate possible.
*/
div_main = DIV_ROUND_UP(parent_rate, 200000);
div_main = clamp(div_main, 1u, 256u);
rate = parent_rate / div_main;
if (rate < 20000 || rate > 200000) {
dev_err(dev, "No valid divider for ADC main clock\n");
return -EINVAL;
}
/* We also need a divider that produces a 10us clock. */
div_10us = DIV_ROUND_UP(rate, 10000);
/* And another, which produces a 1ms clock. */
div_ms = DIV_ROUND_UP(rate, 1000);
writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) |
((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) |
(div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
adc->base + JZ_ADC_REG_ADCLK);
@ -201,6 +258,8 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
.battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
.battery_scale_avail = jz4725b_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
.battery_vref_mode = true,
.has_aux2 = false,
.init_clk_div = jz4725b_adc_init_clk_div,
};
@ -211,9 +270,23 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
.battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
.battery_scale_avail = jz4740_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
.battery_vref_mode = true,
.has_aux2 = false,
.init_clk_div = NULL, /* no ADCLK register on JZ4740 */
};
static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
.battery_high_vref = JZ4770_ADC_BATTERY_VREF,
.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
.battery_raw_avail = jz4770_adc_battery_raw_avail,
.battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
.battery_scale_avail = jz4770_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
.battery_vref_mode = false,
.has_aux2 = true,
.init_clk_div = jz4770_adc_init_clk_div,
};
static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
const int **vals,
@ -239,6 +312,42 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
};
}
static int ingenic_adc_read_chan_info_raw(struct ingenic_adc *adc,
struct iio_chan_spec const *chan,
int *val)
{
int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
/* We cannot sample AUX/AUX2 in parallel. */
mutex_lock(&adc->aux_lock);
if (adc->soc_data->has_aux2 && engine == 0) {
bit = BIT(chan->channel == INGENIC_ADC_AUX2);
ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
}
clk_enable(adc->clk);
ret = ingenic_adc_capture(adc, engine);
if (ret)
goto out;
switch (chan->channel) {
case INGENIC_ADC_AUX:
case INGENIC_ADC_AUX2:
*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
break;
case INGENIC_ADC_BATTERY:
*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
break;
}
ret = IIO_VAL_INT;
out:
clk_disable(adc->clk);
mutex_unlock(&adc->aux_lock);
return ret;
}
static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
@ -246,32 +355,14 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
clk_enable(adc->clk);
ret = ingenic_adc_capture(adc, chan->channel);
if (ret) {
clk_disable(adc->clk);
return ret;
}
switch (chan->channel) {
case INGENIC_ADC_AUX:
*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
break;
case INGENIC_ADC_BATTERY:
*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
break;
}
clk_disable(adc->clk);
return IIO_VAL_INT;
return ingenic_adc_read_chan_info_raw(adc, chan, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case INGENIC_ADC_AUX:
case INGENIC_ADC_AUX2:
*val = JZ_ADC_AUX_VREF;
*val2 = JZ_ADC_AUX_VREF_BITS;
break;
@ -322,6 +413,14 @@ static const struct iio_chan_spec ingenic_channels[] = {
.indexed = 1,
.channel = INGENIC_ADC_BATTERY,
},
{ /* Must always be last in the array. */
.extend_name = "aux2",
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = INGENIC_ADC_AUX2,
},
};
static int ingenic_adc_probe(struct platform_device *pdev)
@ -329,7 +428,6 @@ static int ingenic_adc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct iio_dev *iio_dev;
struct ingenic_adc *adc;
struct resource *mem_base;
const struct ingenic_adc_soc_data *soc_data;
int ret;
@ -343,10 +441,10 @@ static int ingenic_adc_probe(struct platform_device *pdev)
adc = iio_priv(iio_dev);
mutex_init(&adc->lock);
mutex_init(&adc->aux_lock);
adc->soc_data = soc_data;
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(dev, mem_base);
adc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adc->base))
return PTR_ERR(adc->base);
@ -374,6 +472,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
/* Put hardware in a known passive state. */
writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
usleep_range(2000, 3000); /* Must wait at least 2ms. */
clk_disable(adc->clk);
ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
@ -387,6 +486,9 @@ static int ingenic_adc_probe(struct platform_device *pdev)
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = ingenic_channels;
iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
/* Remove AUX2 from the list of supported channels. */
if (!adc->soc_data->has_aux2)
iio_dev->num_channels -= 1;
iio_dev->info = &ingenic_adc_info;
ret = devm_iio_device_register(dev, iio_dev);
@ -400,6 +502,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
static const struct of_device_id ingenic_adc_of_match[] = {
{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
{ },
};
MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);

View File

@ -0,0 +1,262 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ADC driver for Basin Cove PMIC
*
* Copyright (C) 2012 Intel Corporation
* Author: Bin Yang <bin.yang@intel.com>
*
* Rewritten for upstream by:
* Vincent Pelletier <plr.vincent@gmail.com>
* Andy Shevchenko <andriy.shevchenko@linux.intel.com>
*/
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/mfd/intel_soc_pmic_mrfld.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/iio/driver.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <asm/unaligned.h>
#define BCOVE_GPADCREQ 0xDC
#define BCOVE_GPADCREQ_BUSY BIT(0)
#define BCOVE_GPADCREQ_IRQEN BIT(1)
#define BCOVE_ADCIRQ_ALL ( \
BCOVE_ADCIRQ_BATTEMP | \
BCOVE_ADCIRQ_SYSTEMP | \
BCOVE_ADCIRQ_BATTID | \
BCOVE_ADCIRQ_VIBATT | \
BCOVE_ADCIRQ_CCTICK)
#define BCOVE_ADC_TIMEOUT msecs_to_jiffies(1000)
static const u8 mrfld_adc_requests[] = {
BCOVE_ADCIRQ_VIBATT,
BCOVE_ADCIRQ_BATTID,
BCOVE_ADCIRQ_VIBATT,
BCOVE_ADCIRQ_SYSTEMP,
BCOVE_ADCIRQ_BATTEMP,
BCOVE_ADCIRQ_BATTEMP,
BCOVE_ADCIRQ_SYSTEMP,
BCOVE_ADCIRQ_SYSTEMP,
BCOVE_ADCIRQ_SYSTEMP,
};
struct mrfld_adc {
struct regmap *regmap;
struct completion completion;
/* Lock to protect the IPC transfers */
struct mutex lock;
};
static irqreturn_t mrfld_adc_thread_isr(int irq, void *data)
{
struct iio_dev *indio_dev = data;
struct mrfld_adc *adc = iio_priv(indio_dev);
complete(&adc->completion);
return IRQ_HANDLED;
}
static int mrfld_adc_single_conv(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *result)
{
struct mrfld_adc *adc = iio_priv(indio_dev);
struct regmap *regmap = adc->regmap;
unsigned int req;
long timeout;
u8 buf[2];
int ret;
reinit_completion(&adc->completion);
regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0);
regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0);
ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req,
!(req & BCOVE_GPADCREQ_BUSY),
2000, 1000000);
if (ret)
goto done;
req = mrfld_adc_requests[chan->channel];
ret = regmap_write(regmap, BCOVE_GPADCREQ, BCOVE_GPADCREQ_IRQEN | req);
if (ret)
goto done;
timeout = wait_for_completion_interruptible_timeout(&adc->completion,
BCOVE_ADC_TIMEOUT);
if (timeout < 0) {
ret = timeout;
goto done;
}
if (timeout == 0) {
ret = -ETIMEDOUT;
goto done;
}
ret = regmap_bulk_read(regmap, chan->address, buf, 2);
if (ret)
goto done;
*result = get_unaligned_be16(buf);
ret = IIO_VAL_INT;
done:
regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0xff);
regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0xff);
return ret;
}
static int mrfld_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mrfld_adc *adc = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&adc->lock);
ret = mrfld_adc_single_conv(indio_dev, chan, val);
mutex_unlock(&adc->lock);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_info mrfld_adc_iio_info = {
.read_raw = &mrfld_adc_read_raw,
};
#define BCOVE_ADC_CHANNEL(_type, _channel, _datasheet_name, _address) \
{ \
.indexed = 1, \
.type = _type, \
.channel = _channel, \
.address = _address, \
.datasheet_name = _datasheet_name, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static const struct iio_chan_spec mrfld_adc_channels[] = {
BCOVE_ADC_CHANNEL(IIO_VOLTAGE, 0, "CH0", 0xE9),
BCOVE_ADC_CHANNEL(IIO_RESISTANCE, 1, "CH1", 0xEB),
BCOVE_ADC_CHANNEL(IIO_CURRENT, 2, "CH2", 0xED),
BCOVE_ADC_CHANNEL(IIO_TEMP, 3, "CH3", 0xCC),
BCOVE_ADC_CHANNEL(IIO_TEMP, 4, "CH4", 0xC8),
BCOVE_ADC_CHANNEL(IIO_TEMP, 5, "CH5", 0xCA),
BCOVE_ADC_CHANNEL(IIO_TEMP, 6, "CH6", 0xC2),
BCOVE_ADC_CHANNEL(IIO_TEMP, 7, "CH7", 0xC4),
BCOVE_ADC_CHANNEL(IIO_TEMP, 8, "CH8", 0xC6),
};
static struct iio_map iio_maps[] = {
IIO_MAP("CH0", "bcove-battery", "VBATRSLT"),
IIO_MAP("CH1", "bcove-battery", "BATTID"),
IIO_MAP("CH2", "bcove-battery", "IBATRSLT"),
IIO_MAP("CH3", "bcove-temp", "PMICTEMP"),
IIO_MAP("CH4", "bcove-temp", "BATTEMP0"),
IIO_MAP("CH5", "bcove-temp", "BATTEMP1"),
IIO_MAP("CH6", "bcove-temp", "SYSTEMP0"),
IIO_MAP("CH7", "bcove-temp", "SYSTEMP1"),
IIO_MAP("CH8", "bcove-temp", "SYSTEMP2"),
{}
};
static int mrfld_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
struct iio_dev *indio_dev;
struct mrfld_adc *adc;
int irq;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*indio_dev));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
mutex_init(&adc->lock);
init_completion(&adc->completion);
adc->regmap = pmic->regmap;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_adc_thread_isr,
IRQF_ONESHOT | IRQF_SHARED, pdev->name,
indio_dev);
if (ret)
return ret;
platform_set_drvdata(pdev, indio_dev);
indio_dev->dev.parent = dev;
indio_dev->name = pdev->name;
indio_dev->channels = mrfld_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(mrfld_adc_channels);
indio_dev->info = &mrfld_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = iio_map_array_register(indio_dev, iio_maps);
if (ret)
return ret;
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0)
goto err_array_unregister;
return 0;
err_array_unregister:
iio_map_array_unregister(indio_dev);
return ret;
}
static int mrfld_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
iio_map_array_unregister(indio_dev);
return 0;
}
static const struct platform_device_id mrfld_adc_id_table[] = {
{ .name = "mrfld_bcove_adc" },
{}
};
MODULE_DEVICE_TABLE(platform, mrfld_adc_id_table);
static struct platform_driver mrfld_adc_driver = {
.driver = {
.name = "mrfld_bcove_adc",
},
.probe = mrfld_adc_probe,
.remove = mrfld_adc_remove,
.id_table = mrfld_adc_id_table,
};
module_platform_driver(mrfld_adc_driver);
MODULE_AUTHOR("Bin Yang <bin.yang@intel.com>");
MODULE_AUTHOR("Vincent Pelletier <plr.vincent@gmail.com>");
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
MODULE_DESCRIPTION("ADC driver for Basin Cove PMIC");
MODULE_LICENSE("GPL v2");

View File

@ -119,7 +119,6 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct lpc18xx_adc *adc;
struct resource *res;
unsigned int clkdiv;
unsigned long rate;
int ret;
@ -133,8 +132,7 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
adc->dev = &pdev->dev;
mutex_init(&adc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(&pdev->dev, res);
adc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adc->base))
return PTR_ERR(adc->base);

View File

@ -63,12 +63,18 @@ enum max1027_id {
max1027,
max1029,
max1031,
max1227,
max1229,
max1231,
};
static const struct spi_device_id max1027_id[] = {
{"max1027", max1027},
{"max1029", max1029},
{"max1031", max1031},
{"max1227", max1227},
{"max1229", max1229},
{"max1231", max1231},
{}
};
MODULE_DEVICE_TABLE(spi, max1027_id);
@ -78,12 +84,15 @@ static const struct of_device_id max1027_adc_dt_ids[] = {
{ .compatible = "maxim,max1027" },
{ .compatible = "maxim,max1029" },
{ .compatible = "maxim,max1031" },
{ .compatible = "maxim,max1227" },
{ .compatible = "maxim,max1229" },
{ .compatible = "maxim,max1231" },
{},
};
MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
#endif
#define MAX1027_V_CHAN(index) \
#define MAX1027_V_CHAN(index, depth) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
@ -93,7 +102,7 @@ MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
.scan_index = index + 1, \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.realbits = depth, \
.storagebits = 16, \
.shift = 2, \
.endianness = IIO_BE, \
@ -115,52 +124,54 @@ MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids);
}, \
}
#define MAX1X27_CHANNELS(depth) \
MAX1027_T_CHAN, \
MAX1027_V_CHAN(0, depth), \
MAX1027_V_CHAN(1, depth), \
MAX1027_V_CHAN(2, depth), \
MAX1027_V_CHAN(3, depth), \
MAX1027_V_CHAN(4, depth), \
MAX1027_V_CHAN(5, depth), \
MAX1027_V_CHAN(6, depth), \
MAX1027_V_CHAN(7, depth)
#define MAX1X29_CHANNELS(depth) \
MAX1X27_CHANNELS(depth), \
MAX1027_V_CHAN(8, depth), \
MAX1027_V_CHAN(9, depth), \
MAX1027_V_CHAN(10, depth), \
MAX1027_V_CHAN(11, depth)
#define MAX1X31_CHANNELS(depth) \
MAX1X27_CHANNELS(depth), \
MAX1X29_CHANNELS(depth), \
MAX1027_V_CHAN(12, depth), \
MAX1027_V_CHAN(13, depth), \
MAX1027_V_CHAN(14, depth), \
MAX1027_V_CHAN(15, depth)
static const struct iio_chan_spec max1027_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7)
MAX1X27_CHANNELS(10),
};
static const struct iio_chan_spec max1029_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7),
MAX1027_V_CHAN(8),
MAX1027_V_CHAN(9),
MAX1027_V_CHAN(10),
MAX1027_V_CHAN(11)
MAX1X29_CHANNELS(10),
};
static const struct iio_chan_spec max1031_channels[] = {
MAX1027_T_CHAN,
MAX1027_V_CHAN(0),
MAX1027_V_CHAN(1),
MAX1027_V_CHAN(2),
MAX1027_V_CHAN(3),
MAX1027_V_CHAN(4),
MAX1027_V_CHAN(5),
MAX1027_V_CHAN(6),
MAX1027_V_CHAN(7),
MAX1027_V_CHAN(8),
MAX1027_V_CHAN(9),
MAX1027_V_CHAN(10),
MAX1027_V_CHAN(11),
MAX1027_V_CHAN(12),
MAX1027_V_CHAN(13),
MAX1027_V_CHAN(14),
MAX1027_V_CHAN(15)
MAX1X31_CHANNELS(10),
};
static const struct iio_chan_spec max1227_channels[] = {
MAX1X27_CHANNELS(12),
};
static const struct iio_chan_spec max1229_channels[] = {
MAX1X29_CHANNELS(12),
};
static const struct iio_chan_spec max1231_channels[] = {
MAX1X31_CHANNELS(12),
};
static const unsigned long max1027_available_scan_masks[] = {
@ -200,6 +211,21 @@ static const struct max1027_chip_info max1027_chip_info_tbl[] = {
.num_channels = ARRAY_SIZE(max1031_channels),
.available_scan_masks = max1031_available_scan_masks,
},
[max1227] = {
.channels = max1227_channels,
.num_channels = ARRAY_SIZE(max1227_channels),
.available_scan_masks = max1027_available_scan_masks,
},
[max1229] = {
.channels = max1229_channels,
.num_channels = ARRAY_SIZE(max1229_channels),
.available_scan_masks = max1029_available_scan_masks,
},
[max1231] = {
.channels = max1231_channels,
.num_channels = ARRAY_SIZE(max1231_channels),
.available_scan_masks = max1031_available_scan_masks,
},
};
struct max1027_state {
@ -284,7 +310,7 @@ static int max1027_read_raw(struct iio_dev *indio_dev,
break;
case IIO_VOLTAGE:
*val = 2500;
*val2 = 10;
*val2 = chan->scan_type.realbits;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
@ -309,8 +335,11 @@ static int max1027_debugfs_reg_access(struct iio_dev *indio_dev,
struct max1027_state *st = iio_priv(indio_dev);
u8 *val = (u8 *)st->buffer;
if (readval != NULL)
return -EINVAL;
if (readval) {
int ret = spi_read(st->spi, val, 2);
*readval = be16_to_cpu(st->buffer[0]);
return ret;
}
*val = (u8)writeval;
return spi_write(st->spi, val, 1);
@ -427,34 +456,47 @@ static int max1027_probe(struct spi_device *spi)
return -ENOMEM;
}
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
&iio_pollfunc_store_time,
&max1027_trigger_handler, NULL);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
return ret;
if (spi->irq) {
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
&iio_pollfunc_store_time,
&max1027_trigger_handler,
NULL);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to setup buffer\n");
return ret;
}
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
indio_dev->name);
if (st->trig == NULL) {
ret = -ENOMEM;
dev_err(&indio_dev->dev,
"Failed to allocate iio trigger\n");
return ret;
}
st->trig->ops = &max1027_trigger_ops;
st->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
iio_trigger_register(st->trig);
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_FALLING,
spi->dev.driver->name,
st->trig);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
return ret;
}
}
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger",
indio_dev->name);
if (st->trig == NULL) {
ret = -ENOMEM;
dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n");
return ret;
}
st->trig->ops = &max1027_trigger_ops;
st->trig->dev.parent = &spi->dev;
iio_trigger_set_drvdata(st->trig, indio_dev);
iio_trigger_register(st->trig);
ret = devm_request_threaded_irq(&spi->dev, spi->irq,
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_FALLING,
spi->dev.driver->name, st->trig);
/* Internal reset */
st->reg = MAX1027_RST_REG;
ret = spi_write(st->spi, &st->reg, 1);
if (ret < 0) {
dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n");
dev_err(&indio_dev->dev, "Failed to reset the ADC\n");
return ret;
}
@ -480,5 +522,5 @@ static struct spi_driver max1027_driver = {
module_spi_driver(max1027_driver);
MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>");
MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC");
MODULE_DESCRIPTION("MAX1X27/MAX1X29/MAX1X31 ADC");
MODULE_LICENSE("GPL v2");

View File

@ -164,7 +164,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
case mcp3550_60:
case mcp3551:
case mcp3553: {
u32 raw = be32_to_cpup((u32 *)adc->rx_buf);
u32 raw = be32_to_cpup((__be32 *)adc->rx_buf);
if (!(adc->spi->mode & SPI_CPOL))
raw <<= 1; /* strip Data Ready bit in SPI mode 0,0 */

View File

@ -1187,7 +1187,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
const struct meson_sar_adc_data *match_data;
struct meson_sar_adc_priv *priv;
struct iio_dev *indio_dev;
struct resource *res;
void __iomem *base;
int irq, ret;
@ -1214,8 +1213,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &meson_sar_adc_iio_info;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);

View File

@ -237,7 +237,6 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
{
struct mt6577_auxadc_device *adc_dev;
unsigned long adc_clk_rate;
struct resource *res;
struct iio_dev *indio_dev;
int ret;
@ -253,8 +252,7 @@ static int mt6577_auxadc_probe(struct platform_device *pdev)
indio_dev->channels = mt6577_auxadc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
adc_dev->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adc_dev->reg_base)) {
dev_err(&pdev->dev, "failed to get auxadc base address\n");
return PTR_ERR(adc_dev->reg_base);

View File

@ -183,7 +183,6 @@ static int npcm_adc_probe(struct platform_device *pdev)
int irq;
u32 div;
u32 reg_con;
struct resource *res;
struct npcm_adc *info;
struct iio_dev *indio_dev;
struct device *dev = &pdev->dev;
@ -196,8 +195,7 @@ static int npcm_adc_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, res);
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);

View File

@ -481,7 +481,6 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rcar_gyroadc *priv;
struct iio_dev *indio_dev;
struct resource *mem;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
@ -491,8 +490,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
priv = iio_priv(indio_dev);
priv->dev = dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(dev, mem);
priv->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);

View File

@ -477,13 +477,6 @@ static void sc27xx_adc_disable(void *_data)
SC27XX_MODULE_ADC_EN, 0);
}
static void sc27xx_adc_free_hwlock(void *_data)
{
struct hwspinlock *hwlock = _data;
hwspin_lock_free(hwlock);
}
static int sc27xx_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -520,19 +513,12 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
return ret;
}
sc27xx_data->hwlock = hwspin_lock_request_specific(ret);
sc27xx_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
if (!sc27xx_data->hwlock) {
dev_err(dev, "failed to request hwspinlock\n");
return -ENXIO;
}
ret = devm_add_action_or_reset(dev, sc27xx_adc_free_hwlock,
sc27xx_data->hwlock);
if (ret) {
dev_err(dev, "failed to add hwspinlock action\n");
return ret;
}
sc27xx_data->dev = dev;
ret = sc27xx_adc_enable(sc27xx_data);

View File

@ -260,7 +260,6 @@ static int spear_adc_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct spear_adc_state *st;
struct resource *res;
struct iio_dev *indio_dev = NULL;
int ret = -ENODEV;
int irq;
@ -279,8 +278,7 @@ static int spear_adc_probe(struct platform_device *pdev)
* (e.g. SPEAr3xx). Let's provide two register base addresses
* to support multi-arch kernels.
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
st->adc_base_spear6xx = devm_ioremap_resource(&pdev->dev, res);
st->adc_base_spear6xx = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(st->adc_base_spear6xx))
return PTR_ERR(st->adc_base_spear6xx);

View File

@ -38,12 +38,12 @@
#define HAS_ANASWVDD BIT(1)
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* struct stm32_adc_common_regs - stm32 common registers
* @csr: common status register offset
* @ccr: common control register offset
* @eoc1: adc1 end of conversion flag in @csr
* @eoc2: adc2 end of conversion flag in @csr
* @eoc3: adc3 end of conversion flag in @csr
* @eoc1_msk: adc1 end of conversion flag in @csr
* @eoc2_msk: adc2 end of conversion flag in @csr
* @eoc3_msk: adc3 end of conversion flag in @csr
* @ier: interrupt enable register offset for each adc
* @eocie_msk: end of conversion interrupt enable mask in @ier
*/
@ -60,7 +60,7 @@ struct stm32_adc_common_regs {
struct stm32_adc_priv;
/**
* stm32_adc_priv_cfg - stm32 core compatible configuration data
* struct stm32_adc_priv_cfg - stm32 core compatible configuration data
* @regs: common registers for all instances
* @clk_sel: clock selection routine
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
@ -79,6 +79,7 @@ struct stm32_adc_priv_cfg {
* @domain: irq domain reference
* @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
* @max_clk_rate: desired maximum clock rate
* @booster: booster supply reference
* @vdd: vdd supply reference
* @vdda: vdda analog supply reference
@ -95,6 +96,7 @@ struct stm32_adc_priv {
struct irq_domain *domain;
struct clk *aclk;
struct clk *bclk;
u32 max_clk_rate;
struct regulator *booster;
struct regulator *vdd;
struct regulator *vdda;
@ -117,6 +119,7 @@ static int stm32f4_pclk_div[] = {2, 4, 6, 8};
/**
* stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler
* @pdev: platform device
* @priv: stm32 ADC core private data
* Select clock prescaler used for analog conversions, before using ADC.
*/
@ -140,7 +143,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev,
}
for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) {
if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz)
if ((rate / stm32f4_pclk_div[i]) <= priv->max_clk_rate)
break;
}
if (i >= ARRAY_SIZE(stm32f4_pclk_div)) {
@ -229,7 +232,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (ckmode)
continue;
if ((rate / div) <= priv->cfg->max_clk_rate_hz)
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
}
@ -249,7 +252,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (!ckmode)
continue;
if ((rate / div) <= priv->cfg->max_clk_rate_hz)
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
@ -654,6 +657,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct resource *res;
u32 max_rate;
int ret;
if (!pdev->dev.of_node)
@ -730,6 +734,13 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->common.vref_mv = ret / 1000;
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
ret = of_property_read_u32(pdev->dev.of_node, "st,max-clk-rate-hz",
&max_rate);
if (!ret)
priv->max_clk_rate = min(max_rate, priv->cfg->max_clk_rate_hz);
else
priv->max_clk_rate = priv->cfg->max_clk_rate_hz;
ret = priv->cfg->clk_sel(pdev, priv);
if (ret < 0)
goto err_hw_stop;

View File

@ -102,7 +102,7 @@ struct stm32_adc_calib {
};
/**
* stm32_adc_regs - stm32 ADC misc registers & bitfield desc
* struct stm32_adc_regs - stm32 ADC misc registers & bitfield desc
* @reg: register offset
* @mask: bitfield mask
* @shift: left shift
@ -114,7 +114,7 @@ struct stm32_adc_regs {
};
/**
* stm32_adc_regspec - stm32 registers definition, compatible dependent data
* struct stm32_adc_regspec - stm32 registers definition
* @dr: data register offset
* @ier_eoc: interrupt enable register & eocie bitfield
* @isr_eoc: interrupt status register & eoc bitfield
@ -140,7 +140,7 @@ struct stm32_adc_regspec {
struct stm32_adc;
/**
* stm32_adc_cfg - stm32 compatible configuration data
* struct stm32_adc_cfg - stm32 compatible configuration data
* @regs: registers descriptions
* @adc_info: per instance input channels definitions
* @trigs: external trigger sources
@ -183,8 +183,8 @@ struct stm32_adc_cfg {
* @rx_buf: dma rx buffer cpu address
* @rx_dma_buf: dma rx buffer bus address
* @rx_buf_sz: dma rx buffer size
* @difsel bitmask to set single-ended/differential channel
* @pcsel bitmask to preselect channels on some devices
* @difsel: bitmask to set single-ended/differential channel
* @pcsel: bitmask to preselect channels on some devices
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
* @cal: optional calibration data on some devices
* @chan_name: channel name array
@ -254,7 +254,7 @@ static const struct stm32_adc_info stm32h7_adc_info = {
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
};
/**
/*
* stm32f4_sq - describe regular sequence registers
* - L: sequence len (register & bit field)
* - SQ1..SQ16: sequence entries (register & bit field)
@ -301,7 +301,7 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
{}, /* sentinel */
};
/**
/*
* stm32f4_smp_bits[] - describe sampling time register index & bit fields
* Sorted so it can be indexed by channel number.
*/
@ -392,7 +392,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
{},
};
/**
/*
* stm32h7_smp_bits - describe sampling time register index & bit fields
* Sorted so it can be indexed by channel number.
*/
@ -994,6 +994,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
/**
* stm32_adc_get_trig_extsel() - Get external trigger selection
* @indio_dev: IIO device structure
* @trig: trigger
*
* Returns trigger extsel value, if trig matches, -EINVAL otherwise.
@ -1297,6 +1298,10 @@ static int stm32_adc_of_xlate(struct iio_dev *indio_dev,
/**
* stm32_adc_debugfs_reg_access - read or write register value
* @indio_dev: IIO device structure
* @reg: register offset
* @writeval: value to write
* @readval: value to read
*
* To read a value from an ADC register:
* echo [ADC reg offset] > direct_reg_access

View File

@ -175,7 +175,7 @@ static int stmpe_read_raw(struct iio_dev *indio_dev,
static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
{
struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
u16 data;
__be16 data;
if (info->channel <= STMPE_ADC_LAST_NR) {
int int_sta;

View File

@ -495,7 +495,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
ret = twl4030_madc_disable_irq(madc, i);
if (ret < 0)
dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
madc->requests[i].result_pending = 1;
madc->requests[i].result_pending = true;
}
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &madc->requests[i];
@ -507,8 +507,8 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw);
/* Free request */
r->result_pending = 0;
r->active = 0;
r->result_pending = false;
r->active = false;
}
mutex_unlock(&madc->lock);
@ -521,15 +521,15 @@ err_i2c:
*/
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
r = &madc->requests[i];
if (r->active == 0)
if (!r->active)
continue;
method = &twl4030_conversion_methods[r->method];
/* Read results */
len = twl4030_madc_read_channels(madc, method->rbase,
r->channels, r->rbuf, r->raw);
/* Free request */
r->result_pending = 0;
r->active = 0;
r->result_pending = false;
r->active = false;
}
mutex_unlock(&madc->lock);
@ -652,16 +652,16 @@ static int twl4030_madc_conversion(struct twl4030_madc_request *req)
ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
if (ret < 0)
goto out;
twl4030_madc->requests[req->method].active = 1;
twl4030_madc->requests[req->method].active = true;
/* Wait until conversion is ready (ctrl register returns EOC) */
ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
if (ret) {
twl4030_madc->requests[req->method].active = 0;
twl4030_madc->requests[req->method].active = false;
goto out;
}
ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
req->channels, req->rbuf, req->raw);
twl4030_madc->requests[req->method].active = 0;
twl4030_madc->requests[req->method].active = false;
out:
mutex_unlock(&twl4030_madc->lock);

View File

@ -802,7 +802,6 @@ static int vf610_adc_probe(struct platform_device *pdev)
{
struct vf610_adc *info;
struct iio_dev *indio_dev;
struct resource *mem;
int irq;
int ret;
@ -815,8 +814,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);

View File

@ -1150,7 +1150,6 @@ static int xadc_probe(struct platform_device *pdev)
const struct of_device_id *id;
struct iio_dev *indio_dev;
unsigned int bipolar_mask;
struct resource *mem;
unsigned int conf0;
struct xadc *xadc;
int ret;
@ -1180,8 +1179,7 @@ static int xadc_probe(struct platform_device *pdev)
spin_lock_init(&xadc->lock);
INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xadc->base = devm_ioremap_resource(&pdev->dev, mem);
xadc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xadc->base))
return PTR_ERR(xadc->base);

View File

@ -323,16 +323,16 @@ static int atlas_buffer_predisable(struct iio_dev *indio_dev)
struct atlas_data *data = iio_priv(indio_dev);
int ret;
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret)
return ret;
ret = atlas_set_interrupt(data, false);
if (ret)
return ret;
pm_runtime_mark_last_busy(&data->client->dev);
return pm_runtime_put_autosuspend(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
if (ret)
return ret;
return iio_triggered_buffer_predisable(indio_dev);
}
static const struct iio_trigger_ops atlas_interrupt_trigger_ops = {

View File

@ -483,7 +483,7 @@ static void sgp_init(struct sgp_data *data)
data->iaq_defval_skip_jiffies =
43 * data->measure_interval_jiffies;
break;
};
}
}
static const struct iio_info sgp_info = {

View File

@ -117,7 +117,7 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
break;
case SPS30_READ_AUTO_CLEANING_PERIOD:
buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
buf[1] = (u8)SPS30_AUTO_CLEANING_PERIOD;
buf[1] = (u8)(SPS30_AUTO_CLEANING_PERIOD & 0xff);
/* fall through */
case SPS30_READ_DATA_READY_FLAG:
case SPS30_READ_DATA:

View File

@ -60,8 +60,8 @@ config AD5446
help
Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612,
AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5600, AD5601, AD5602, AD5611,
AD5612, AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs
as well as Texas Instruments DAC081S101, DAC101S101, DAC121S101.
To compile this driver as a module, choose M here: the

View File

@ -327,6 +327,7 @@ enum ad5446_supported_spi_device_ids {
ID_AD5541A,
ID_AD5512A,
ID_AD5553,
ID_AD5600,
ID_AD5601,
ID_AD5611,
ID_AD5621,
@ -381,6 +382,10 @@ static const struct ad5446_chip_info ad5446_spi_chip_info[] = {
.channel = AD5446_CHANNEL(14, 16, 0),
.write = ad5446_write,
},
[ID_AD5600] = {
.channel = AD5446_CHANNEL(16, 16, 0),
.write = ad5446_write,
},
[ID_AD5601] = {
.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
.write = ad5446_write,
@ -448,6 +453,7 @@ static const struct spi_device_id ad5446_spi_ids[] = {
{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
{"ad5553", ID_AD5553},
{"ad5600", ID_AD5600},
{"ad5601", ID_AD5601},
{"ad5611", ID_AD5611},
{"ad5621", ID_AD5621},

View File

@ -41,6 +41,7 @@ struct ad7303_state {
struct regulator *vdd_reg;
struct regulator *vref_reg;
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@ -79,7 +80,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
if (ret)
return ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
if (pwr_down)
st->config |= AD7303_CFG_POWER_DOWN(chan->channel);
@ -90,7 +91,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev,
* mode, so just write one of the DAC channels again */
ad7303_write(st, chan->channel, st->dac_cache[chan->channel]);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return len;
}
@ -116,7 +117,9 @@ static int ad7303_read_raw(struct iio_dev *indio_dev,
switch (info) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
*val = st->dac_cache[chan->channel];
mutex_unlock(&st->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
vref_uv = ad7303_get_vref(st, chan);
@ -144,11 +147,11 @@ static int ad7303_write_raw(struct iio_dev *indio_dev,
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad7303_write(st, chan->address, val);
if (ret == 0)
st->dac_cache[chan->channel] = val;
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
break;
default:
ret = -EINVAL;
@ -211,6 +214,8 @@ static int ad7303_probe(struct spi_device *spi)
st->spi = spi;
mutex_init(&st->lock);
st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd");
if (IS_ERR(st->vdd_reg))
return PTR_ERR(st->vdd_reg);

View File

@ -106,7 +106,6 @@ static int lpc18xx_dac_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct lpc18xx_dac *dac;
struct resource *res;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
@ -117,8 +116,7 @@ static int lpc18xx_dac_probe(struct platform_device *pdev)
dac = iio_priv(indio_dev);
mutex_init(&dac->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dac->base = devm_ioremap_resource(&pdev->dev, res);
dac->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dac->base))
return PTR_ERR(dac->base);

View File

@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@ -50,6 +51,41 @@ static const struct regmap_config stm32_dac_regmap_cfg = {
.max_register = 0x3fc,
};
static int stm32_dac_core_hw_start(struct device *dev)
{
struct stm32_dac_common *common = dev_get_drvdata(dev);
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
int ret;
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(priv->pclk);
if (ret < 0) {
dev_err(dev, "pclk enable failed: %d\n", ret);
goto err_regulator_disable;
}
return 0;
err_regulator_disable:
regulator_disable(priv->vref);
return ret;
}
static void stm32_dac_core_hw_stop(struct device *dev)
{
struct stm32_dac_common *common = dev_get_drvdata(dev);
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
clk_disable_unprepare(priv->pclk);
regulator_disable(priv->vref);
}
static int stm32_dac_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -66,6 +102,8 @@ static int stm32_dac_probe(struct platform_device *pdev)
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
cfg = (const struct stm32_dac_cfg *)
of_match_device(dev->driver->of_match_table, dev)->data;
@ -74,11 +112,19 @@ static int stm32_dac_probe(struct platform_device *pdev)
if (IS_ERR(mmio))
return PTR_ERR(mmio);
regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
regmap = devm_regmap_init_mmio_clk(dev, "pclk", mmio,
&stm32_dac_regmap_cfg);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
priv->common.regmap = regmap;
priv->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(priv->pclk)) {
ret = PTR_ERR(priv->pclk);
dev_err(dev, "pclk get failed\n");
return ret;
}
priv->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(priv->vref)) {
ret = PTR_ERR(priv->vref);
@ -86,33 +132,22 @@ static int stm32_dac_probe(struct platform_device *pdev)
return ret;
}
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed\n");
return ret;
}
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
ret = stm32_dac_core_hw_start(dev);
if (ret)
goto err_pm_stop;
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
dev_err(dev, "vref get voltage failed, %d\n", ret);
goto err_vref;
goto err_hw_stop;
}
priv->common.vref_mv = ret / 1000;
dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
priv->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(priv->pclk)) {
ret = PTR_ERR(priv->pclk);
dev_err(dev, "pclk get failed\n");
goto err_vref;
}
ret = clk_prepare_enable(priv->pclk);
if (ret < 0) {
dev_err(dev, "pclk enable failed\n");
goto err_vref;
}
priv->rst = devm_reset_control_get_exclusive(dev, NULL);
if (!IS_ERR(priv->rst)) {
reset_control_assert(priv->rst);
@ -128,39 +163,79 @@ static int stm32_dac_probe(struct platform_device *pdev)
priv->common.hfsel ?
STM32H7_DAC_CR_HFSEL : 0);
if (ret)
goto err_pclk;
goto err_hw_stop;
}
platform_set_drvdata(pdev, &priv->common);
ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
if (ret < 0) {
dev_err(dev, "failed to populate DT children\n");
goto err_pclk;
goto err_hw_stop;
}
pm_runtime_put(dev);
return 0;
err_pclk:
clk_disable_unprepare(priv->pclk);
err_vref:
regulator_disable(priv->vref);
err_hw_stop:
stm32_dac_core_hw_stop(dev);
err_pm_stop:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
return ret;
}
static int stm32_dac_remove(struct platform_device *pdev)
{
struct stm32_dac_common *common = platform_get_drvdata(pdev);
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
pm_runtime_get_sync(&pdev->dev);
of_platform_depopulate(&pdev->dev);
clk_disable_unprepare(priv->pclk);
regulator_disable(priv->vref);
stm32_dac_core_hw_stop(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return 0;
}
static int __maybe_unused stm32_dac_core_resume(struct device *dev)
{
struct stm32_dac_common *common = dev_get_drvdata(dev);
struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
int ret;
if (priv->common.hfsel) {
/* restore hfsel (maybe lost under low power state) */
ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR,
STM32H7_DAC_CR_HFSEL,
STM32H7_DAC_CR_HFSEL);
if (ret)
return ret;
}
return pm_runtime_force_resume(dev);
}
static int __maybe_unused stm32_dac_core_runtime_suspend(struct device *dev)
{
stm32_dac_core_hw_stop(dev);
return 0;
}
static int __maybe_unused stm32_dac_core_runtime_resume(struct device *dev)
{
return stm32_dac_core_hw_start(dev);
}
static const struct dev_pm_ops stm32_dac_core_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume)
SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend,
stm32_dac_core_runtime_resume,
NULL)
};
static const struct stm32_dac_cfg stm32h7_dac_cfg = {
.has_hfsel = true,
};
@ -182,6 +257,7 @@ static struct platform_driver stm32_dac_driver = {
.driver = {
.name = "stm32-dac-core",
.of_match_table = stm32_dac_of_match,
.pm = &stm32_dac_core_pm_ops,
},
};
module_platform_driver(stm32_dac_driver);

View File

@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include "stm32-dac-core.h"
@ -20,6 +21,8 @@
#define STM32_DAC_CHANNEL_2 2
#define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1)
#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000
/**
* struct stm32_dac - private data of DAC driver
* @common: reference to DAC common data
@ -49,15 +52,34 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
bool enable)
{
struct stm32_dac *dac = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
u32 en = enable ? msk : 0;
int ret;
/* already enabled / disabled ? */
mutex_lock(&indio_dev->mlock);
ret = stm32_dac_is_enabled(indio_dev, ch);
if (ret < 0 || enable == !!ret) {
mutex_unlock(&indio_dev->mlock);
return ret < 0 ? ret : 0;
}
if (enable) {
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
mutex_unlock(&indio_dev->mlock);
return ret;
}
}
ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en);
mutex_unlock(&indio_dev->mlock);
if (ret < 0) {
dev_err(&indio_dev->dev, "%s failed\n", en ?
"Enable" : "Disable");
return ret;
goto err_put_pm;
}
/*
@ -68,7 +90,20 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
if (en && dac->common->hfsel)
udelay(1);
if (!enable) {
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
return 0;
err_put_pm:
if (enable) {
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
return ret;
}
static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
@ -272,6 +307,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
static int stm32_dac_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
struct stm32_dac *dac;
int ret;
@ -296,9 +332,61 @@ static int stm32_dac_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
return devm_iio_device_register(&pdev->dev, indio_dev);
/* Get stm32-dac-core PM online */
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
ret = iio_device_register(indio_dev);
if (ret)
goto err_pm_put;
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
err_pm_put:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
return ret;
}
static int stm32_dac_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
iio_device_unregister(indio_dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return 0;
}
static int __maybe_unused stm32_dac_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
int channel = indio_dev->channels[0].channel;
int ret;
/* Ensure DAC is disabled before suspend */
ret = stm32_dac_is_enabled(indio_dev, channel);
if (ret)
return ret < 0 ? ret : -EBUSY;
return pm_runtime_force_suspend(dev);
}
static const struct dev_pm_ops stm32_dac_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume)
};
static const struct of_device_id stm32_dac_of_match[] = {
{ .compatible = "st,stm32-dac", },
{},
@ -307,9 +395,11 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
static struct platform_driver stm32_dac_driver = {
.probe = stm32_dac_probe,
.remove = stm32_dac_remove,
.driver = {
.name = "stm32-dac",
.of_match_table = stm32_dac_of_match,
.pm = &stm32_dac_pm_ops,
},
};
module_platform_driver(stm32_dac_driver);

View File

@ -172,7 +172,6 @@ static int vf610_dac_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct vf610_dac *info;
struct resource *mem;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev,
@ -185,8 +184,7 @@ static int vf610_dac_probe(struct platform_device *pdev)
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem);
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);

View File

@ -38,10 +38,12 @@ struct adis16080_chip_info {
* @us: actual spi_device to write data
* @info: chip specific parameters
* @buf: transmit or receive buffer
* @lock lock to protect buffer during reads
**/
struct adis16080_state {
struct spi_device *us;
const struct adis16080_chip_info *info;
struct mutex lock;
__be16 buf ____cacheline_aligned;
};
@ -82,9 +84,9 @@ static int adis16080_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = adis16080_read_sample(indio_dev, chan->address, val);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret ? ret : IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
@ -196,6 +198,8 @@ static int adis16080_probe(struct spi_device *spi)
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
mutex_init(&st->lock);
/* Allocate the comms buffers */
st->us = spi;
st->info = &adis16080_chip_info[id->driver_data];

View File

@ -76,9 +76,7 @@ static int adis16130_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
ret = adis16130_spi_read(indio_dev, chan->address, &temp);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
*val = temp;

View File

@ -80,19 +80,19 @@ static ssize_t adis16136_show_serial(struct file *file,
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM,
&serial);
if (ret < 0)
if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1);
if (ret < 0)
if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2);
if (ret < 0)
if (ret)
return ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3);
if (ret < 0)
if (ret)
return ret;
len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2,
@ -116,7 +116,7 @@ static int adis16136_show_product_id(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID,
&prod_id);
if (ret < 0)
if (ret)
return ret;
*val = prod_id;
@ -134,7 +134,7 @@ static int adis16136_show_flash_count(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
if (ret)
return ret;
*val = flash_count;
@ -191,7 +191,7 @@ static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
if (ret < 0)
if (ret)
return ret;
*freq = 32768 / (t + 1);
@ -228,7 +228,7 @@ static ssize_t adis16136_read_frequency(struct device *dev,
int ret;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
if (ret)
return ret;
return sprintf(buf, "%d\n", freq);
@ -256,7 +256,7 @@ static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
int i, ret;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
if (ret)
return ret;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
@ -277,11 +277,11 @@ static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
mutex_lock(&indio_dev->mlock);
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
if (ret < 0)
if (ret)
goto err_unlock;
ret = adis16136_get_freq(adis16136, &freq);
if (ret < 0)
if (ret)
goto err_unlock;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
@ -318,7 +318,7 @@ static int adis16136_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
ret = adis_read_reg_32(&adis16136->adis,
ADIS16136_REG_GYRO_OFF2, &val32);
if (ret < 0)
if (ret)
return ret;
*val = sign_extend32(val32, 31);

View File

@ -154,7 +154,7 @@ static int itg3200_write_raw(struct iio_dev *indio_dev,
t);
mutex_unlock(&indio_dev->mlock);
return ret;
return ret;
default:
return -EINVAL;

View File

@ -543,7 +543,7 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p)
toread = bytes_per_datum;
offset = 1;
/* Put in some dummy value */
fifo_values[0] = 0xAAAA;
fifo_values[0] = cpu_to_be16(0xAAAA);
}
ret = regmap_bulk_read(mpu3050->map,

View File

@ -14,7 +14,6 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>

View File

@ -278,31 +278,34 @@ static int hdc100x_buffer_postenable(struct iio_dev *indio_dev)
struct hdc100x_data *data = iio_priv(indio_dev);
int ret;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret)
return ret;
/* Buffer is enabled. First set ACQ Mode, then attach poll func */
mutex_lock(&data->lock);
ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE,
HDC100X_REG_CONFIG_ACQ_MODE);
mutex_unlock(&data->lock);
if (ret)
return ret;
iio_triggered_buffer_predisable(indio_dev);
return iio_triggered_buffer_postenable(indio_dev);
return ret;
}
static int hdc100x_buffer_predisable(struct iio_dev *indio_dev)
{
struct hdc100x_data *data = iio_priv(indio_dev);
int ret;
/* First detach poll func, then reset ACQ mode. OK to disable buffer */
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret)
return ret;
int ret, ret2;
mutex_lock(&data->lock);
ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0);
mutex_unlock(&data->lock);
ret2 = iio_triggered_buffer_predisable(indio_dev);
if (ret == 0)
ret = ret2;
return ret;
}

View File

@ -40,6 +40,33 @@ config ADIS16480
source "drivers/iio/imu/bmi160/Kconfig"
config FXOS8700
tristate
config FXOS8700_I2C
tristate "NXP FXOS8700 I2C driver"
depends on I2C
select FXOS8700
select REGMAP_I2C
help
Say yes here to build support for the NXP FXOS8700 m+g combo
sensor on I2C.
This driver can also be built as a module. If so, the module will be
called fxos8700_i2c.
config FXOS8700_SPI
tristate "NXP FXOS8700 SPI driver"
depends on SPI
select FXOS8700
select REGMAP_SPI
help
Say yes here to build support for the NXP FXOS8700 m+g combo
sensor on SPI.
This driver can also be built as a module. If so, the module will be
called fxos8700_spi.
config KMX61
tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
depends on I2C

View File

@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
obj-y += bmi160/
obj-$(CONFIG_FXOS8700) += fxos8700_core.o
obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o

View File

@ -229,7 +229,8 @@ int adis_debugfs_reg_access(struct iio_dev *indio_dev,
int ret;
ret = adis_read_reg_16(adis, reg, &val16);
*readval = val16;
if (ret == 0)
*readval = val16;
return ret;
} else {
@ -286,7 +287,7 @@ int adis_check_status(struct adis *adis)
int i;
ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
if (ret < 0)
if (ret)
return ret;
status &= adis->data->status_error_mask;

View File

@ -217,16 +217,16 @@ static ssize_t adis16400_show_serial_number(struct file *file,
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID1, &lot1);
if (ret < 0)
if (ret)
return ret;
ret = adis_read_reg_16(&st->adis, ADIS16334_LOT_ID2, &lot2);
if (ret < 0)
if (ret)
return ret;
ret = adis_read_reg_16(&st->adis, ADIS16334_SERIAL_NUMBER,
&serial_number);
if (ret < 0)
if (ret)
return ret;
len = snprintf(buf, sizeof(buf), "%.4x-%.4x-%.4x\n", lot1, lot2,
@ -249,7 +249,7 @@ static int adis16400_show_product_id(void *arg, u64 *val)
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16400_PRODUCT_ID, &prod_id);
if (ret < 0)
if (ret)
return ret;
*val = prod_id;
@ -266,7 +266,7 @@ static int adis16400_show_flash_count(void *arg, u64 *val)
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16400_FLASH_CNT, &flash_count);
if (ret < 0)
if (ret)
return ret;
*val = flash_count;
@ -327,7 +327,7 @@ static int adis16334_get_freq(struct adis16400_state *st)
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret < 0)
if (ret)
return ret;
t >>= ADIS16334_RATE_DIV_SHIFT;
@ -359,7 +359,7 @@ static int adis16400_get_freq(struct adis16400_state *st)
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret < 0)
if (ret)
return ret;
sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 52851 : 1638404;
@ -416,7 +416,7 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
}
ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
if (ret < 0)
if (ret)
return ret;
ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
@ -615,7 +615,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
ret = adis_read_reg_16(&st->adis,
ADIS16400_SENS_AVG,
&val16);
if (ret < 0) {
if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret;
}
@ -626,12 +626,12 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val2 = (ret % 1000) * 1000;
}
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
if (ret)
return ret;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = st->variant->get_freq(st);
if (ret < 0)
if (ret)
return ret;
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;

View File

@ -80,7 +80,7 @@ static int adis16460_show_serial_number(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_SERIAL_NUM,
&serial);
if (ret < 0)
if (ret)
return ret;
*val = serial;
@ -98,7 +98,7 @@ static int adis16460_show_product_id(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_PROD_ID,
&prod_id);
if (ret < 0)
if (ret)
return ret;
*val = prod_id;
@ -116,7 +116,7 @@ static int adis16460_show_flash_count(void *arg, u64 *val)
ret = adis_read_reg_32(&adis16460->adis, ADIS16460_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
if (ret)
return ret;
*val = flash_count;
@ -176,7 +176,7 @@ static int adis16460_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
unsigned int freq;
ret = adis_read_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, &t);
if (ret < 0)
if (ret)
return ret;
freq = 2048000 / (t + 1);

View File

@ -181,7 +181,7 @@ static ssize_t adis16480_show_firmware_revision(struct file *file,
int ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev);
if (ret < 0)
if (ret)
return ret;
len = scnprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
@ -206,11 +206,11 @@ static ssize_t adis16480_show_firmware_date(struct file *file,
int ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year);
if (ret < 0)
if (ret)
return ret;
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md);
if (ret < 0)
if (ret)
return ret;
len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n",
@ -234,7 +234,7 @@ static int adis16480_show_serial_number(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM,
&serial);
if (ret < 0)
if (ret)
return ret;
*val = serial;
@ -252,7 +252,7 @@ static int adis16480_show_product_id(void *arg, u64 *val)
ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID,
&prod_id);
if (ret < 0)
if (ret)
return ret;
*val = prod_id;
@ -270,7 +270,7 @@ static int adis16480_show_flash_count(void *arg, u64 *val)
ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
if (ret)
return ret;
*val = flash_count;
@ -353,7 +353,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
struct adis16480 *st = iio_priv(indio_dev);
uint16_t t;
int ret;
unsigned freq;
unsigned int freq;
unsigned int reg;
if (st->clk_mode == ADIS16480_CLK_PPS)
@ -362,7 +362,7 @@ static int adis16480_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
reg = ADIS16480_REG_DEC_RATE;
ret = adis_read_reg_16(&st->adis, reg, &t);
if (ret < 0)
if (ret)
return ret;
/*
@ -454,18 +454,20 @@ static int adis16480_get_calibbias(struct iio_dev *indio_dev,
case IIO_MAGN:
case IIO_PRESSURE:
ret = adis_read_reg_16(&st->adis, reg, &val16);
*bias = sign_extend32(val16, 15);
if (ret == 0)
*bias = sign_extend32(val16, 15);
break;
case IIO_ANGL_VEL:
case IIO_ACCEL:
ret = adis_read_reg_32(&st->adis, reg, &val32);
*bias = sign_extend32(val32, 31);
if (ret == 0)
*bias = sign_extend32(val32, 31);
break;
default:
ret = -EINVAL;
ret = -EINVAL;
}
if (ret < 0)
if (ret)
return ret;
return IIO_VAL_INT;
@ -492,7 +494,7 @@ static int adis16480_get_calibscale(struct iio_dev *indio_dev,
int ret;
ret = adis_read_reg_16(&st->adis, reg, &val16);
if (ret < 0)
if (ret)
return ret;
*scale = sign_extend32(val16, 15);
@ -538,7 +540,7 @@ static int adis16480_get_filter_freq(struct iio_dev *indio_dev,
enable_mask = BIT(offset + 2);
ret = adis_read_reg_16(&st->adis, reg, &val);
if (ret < 0)
if (ret)
return ret;
if (!(val & enable_mask))
@ -564,7 +566,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
enable_mask = BIT(offset + 2);
ret = adis_read_reg_16(&st->adis, reg, &val);
if (ret < 0)
if (ret)
return ret;
if (freq == 0) {
@ -623,9 +625,13 @@ static int adis16480_read_raw(struct iio_dev *indio_dev,
*val2 = (st->chip_info->temp_scale % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_PRESSURE:
*val = 0;
*val2 = 4000; /* 40ubar = 0.004 kPa */
return IIO_VAL_INT_PLUS_MICRO;
/*
* max scale is 1310 mbar
* max raw value is 32767 shifted for 32bits
*/
*val = 131; /* 1310mbar = 131 kPa */
*val2 = 32767 << 16;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
@ -786,13 +792,14 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
/*
* storing the value in rad/degree and the scale in degree
* gives us the result in rad and better precession than
* storing the scale directly in rad.
* Typically we do IIO_RAD_TO_DEGREE in the denominator, which
* is exactly the same as IIO_DEGREE_TO_RAD in numerator, since
* it gives better approximation. However, in this case we
* cannot do it since it would not fit in a 32bit variable.
*/
.gyro_max_val = IIO_RAD_TO_DEGREE(22887),
.gyro_max_scale = 300,
.accel_max_val = IIO_M_S_2_TO_G(21973),
.gyro_max_val = 22887 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(300),
.accel_max_val = IIO_M_S_2_TO_G(21973 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.int_clk = 2460000,
@ -802,9 +809,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16480] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(12500),
.gyro_max_val = 22500 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(12500 << 16),
.accel_max_scale = 10,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.int_clk = 2460000,
@ -814,9 +821,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16485] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(20000),
.gyro_max_val = 22500 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 5,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.int_clk = 2460000,
@ -826,9 +833,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16488] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(22500),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(22500),
.gyro_max_val = 22500 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(22500 << 16),
.accel_max_scale = 18,
.temp_scale = 5650, /* 5.65 milli degree Celsius */
.int_clk = 2460000,
@ -838,9 +845,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16495_1] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
.gyro_max_scale = 125,
.accel_max_val = IIO_M_S_2_TO_G(32000),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.int_clk = 4250000,
@ -851,9 +858,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16495_2] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(18000),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(32000),
.gyro_max_val = 18000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.int_clk = 4250000,
@ -864,9 +871,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16495_3] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
.gyro_max_scale = 2000,
.accel_max_val = IIO_M_S_2_TO_G(32000),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 8,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.int_clk = 4250000,
@ -877,9 +884,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16497_1] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
.gyro_max_scale = 125,
.accel_max_val = IIO_M_S_2_TO_G(32000),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(125),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.int_clk = 4250000,
@ -890,9 +897,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16497_2] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(18000),
.gyro_max_scale = 450,
.accel_max_val = IIO_M_S_2_TO_G(32000),
.gyro_max_val = 18000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(450),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.int_clk = 4250000,
@ -903,9 +910,9 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16497_3] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = IIO_RAD_TO_DEGREE(20000),
.gyro_max_scale = 2000,
.accel_max_val = IIO_M_S_2_TO_G(32000),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(2000),
.accel_max_val = IIO_M_S_2_TO_G(32000 << 16),
.accel_max_scale = 40,
.temp_scale = 12500, /* 12.5 milli degree Celsius */
.int_clk = 4250000,
@ -919,6 +926,7 @@ static const struct iio_info adis16480_info = {
.read_raw = &adis16480_read_raw,
.write_raw = &adis16480_write_raw,
.update_scan_mode = adis_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
static int adis16480_stop_device(struct iio_dev *indio_dev)
@ -940,7 +948,7 @@ static int adis16480_enable_irq(struct adis *adis, bool enable)
int ret;
ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
if (ret < 0)
if (ret)
return ret;
val &= ~ADIS16480_DRDY_EN_MSK;
@ -1118,7 +1126,7 @@ static int adis16480_ext_clk_config(struct adis16480 *st,
int ret;
ret = adis_read_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, &val);
if (ret < 0)
if (ret)
return ret;
pin = adis16480_of_get_ext_clk_pin(st, of_node);
@ -1144,7 +1152,7 @@ static int adis16480_ext_clk_config(struct adis16480 *st,
val |= mode;
ret = adis_write_reg_16(&st->adis, ADIS16480_REG_FNCTIO_CTRL, val);
if (ret < 0)
if (ret)
return ret;
return clk_prepare_enable(st->ext_clk);

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef FXOS8700_H_
#define FXOS8700_H_
extern const struct regmap_config fxos8700_regmap_config;
int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
#endif /* FXOS8700_H_ */

View File

@ -0,0 +1,649 @@
// SPDX-License-Identifier: GPL-2.0
/*
* FXOS8700 - NXP IMU (accelerometer plus magnetometer)
*
* IIO core driver for FXOS8700, with support for I2C/SPI busses
*
* TODO: Buffer, trigger, and IRQ support
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "fxos8700.h"
/* Register Definitions */
#define FXOS8700_STATUS 0x00
#define FXOS8700_OUT_X_MSB 0x01
#define FXOS8700_OUT_X_LSB 0x02
#define FXOS8700_OUT_Y_MSB 0x03
#define FXOS8700_OUT_Y_LSB 0x04
#define FXOS8700_OUT_Z_MSB 0x05
#define FXOS8700_OUT_Z_LSB 0x06
#define FXOS8700_F_SETUP 0x09
#define FXOS8700_TRIG_CFG 0x0a
#define FXOS8700_SYSMOD 0x0b
#define FXOS8700_INT_SOURCE 0x0c
#define FXOS8700_WHO_AM_I 0x0d
#define FXOS8700_XYZ_DATA_CFG 0x0e
#define FXOS8700_HP_FILTER_CUTOFF 0x0f
#define FXOS8700_PL_STATUS 0x10
#define FXOS8700_PL_CFG 0x11
#define FXOS8700_PL_COUNT 0x12
#define FXOS8700_PL_BF_ZCOMP 0x13
#define FXOS8700_PL_THS_REG 0x14
#define FXOS8700_A_FFMT_CFG 0x15
#define FXOS8700_A_FFMT_SRC 0x16
#define FXOS8700_A_FFMT_THS 0x17
#define FXOS8700_A_FFMT_COUNT 0x18
#define FXOS8700_TRANSIENT_CFG 0x1d
#define FXOS8700_TRANSIENT_SRC 0x1e
#define FXOS8700_TRANSIENT_THS 0x1f
#define FXOS8700_TRANSIENT_COUNT 0x20
#define FXOS8700_PULSE_CFG 0x21
#define FXOS8700_PULSE_SRC 0x22
#define FXOS8700_PULSE_THSX 0x23
#define FXOS8700_PULSE_THSY 0x24
#define FXOS8700_PULSE_THSZ 0x25
#define FXOS8700_PULSE_TMLT 0x26
#define FXOS8700_PULSE_LTCY 0x27
#define FXOS8700_PULSE_WIND 0x28
#define FXOS8700_ASLP_COUNT 0x29
#define FXOS8700_CTRL_REG1 0x2a
#define FXOS8700_CTRL_REG2 0x2b
#define FXOS8700_CTRL_REG3 0x2c
#define FXOS8700_CTRL_REG4 0x2d
#define FXOS8700_CTRL_REG5 0x2e
#define FXOS8700_OFF_X 0x2f
#define FXOS8700_OFF_Y 0x30
#define FXOS8700_OFF_Z 0x31
#define FXOS8700_M_DR_STATUS 0x32
#define FXOS8700_M_OUT_X_MSB 0x33
#define FXOS8700_M_OUT_X_LSB 0x34
#define FXOS8700_M_OUT_Y_MSB 0x35
#define FXOS8700_M_OUT_Y_LSB 0x36
#define FXOS8700_M_OUT_Z_MSB 0x37
#define FXOS8700_M_OUT_Z_LSB 0x38
#define FXOS8700_CMP_X_MSB 0x39
#define FXOS8700_CMP_X_LSB 0x3a
#define FXOS8700_CMP_Y_MSB 0x3b
#define FXOS8700_CMP_Y_LSB 0x3c
#define FXOS8700_CMP_Z_MSB 0x3d
#define FXOS8700_CMP_Z_LSB 0x3e
#define FXOS8700_M_OFF_X_MSB 0x3f
#define FXOS8700_M_OFF_X_LSB 0x40
#define FXOS8700_M_OFF_Y_MSB 0x41
#define FXOS8700_M_OFF_Y_LSB 0x42
#define FXOS8700_M_OFF_Z_MSB 0x43
#define FXOS8700_M_OFF_Z_LSB 0x44
#define FXOS8700_MAX_X_MSB 0x45
#define FXOS8700_MAX_X_LSB 0x46
#define FXOS8700_MAX_Y_MSB 0x47
#define FXOS8700_MAX_Y_LSB 0x48
#define FXOS8700_MAX_Z_MSB 0x49
#define FXOS8700_MAX_Z_LSB 0x4a
#define FXOS8700_MIN_X_MSB 0x4b
#define FXOS8700_MIN_X_LSB 0x4c
#define FXOS8700_MIN_Y_MSB 0x4d
#define FXOS8700_MIN_Y_LSB 0x4e
#define FXOS8700_MIN_Z_MSB 0x4f
#define FXOS8700_MIN_Z_LSB 0x50
#define FXOS8700_TEMP 0x51
#define FXOS8700_M_THS_CFG 0x52
#define FXOS8700_M_THS_SRC 0x53
#define FXOS8700_M_THS_X_MSB 0x54
#define FXOS8700_M_THS_X_LSB 0x55
#define FXOS8700_M_THS_Y_MSB 0x56
#define FXOS8700_M_THS_Y_LSB 0x57
#define FXOS8700_M_THS_Z_MSB 0x58
#define FXOS8700_M_THS_Z_LSB 0x59
#define FXOS8700_M_THS_COUNT 0x5a
#define FXOS8700_M_CTRL_REG1 0x5b
#define FXOS8700_M_CTRL_REG2 0x5c
#define FXOS8700_M_CTRL_REG3 0x5d
#define FXOS8700_M_INT_SRC 0x5e
#define FXOS8700_A_VECM_CFG 0x5f
#define FXOS8700_A_VECM_THS_MSB 0x60
#define FXOS8700_A_VECM_THS_LSB 0x61
#define FXOS8700_A_VECM_CNT 0x62
#define FXOS8700_A_VECM_INITX_MSB 0x63
#define FXOS8700_A_VECM_INITX_LSB 0x64
#define FXOS8700_A_VECM_INITY_MSB 0x65
#define FXOS8700_A_VECM_INITY_LSB 0x66
#define FXOS8700_A_VECM_INITZ_MSB 0x67
#define FXOS8700_A_VECM_INITZ_LSB 0x68
#define FXOS8700_M_VECM_CFG 0x69
#define FXOS8700_M_VECM_THS_MSB 0x6a
#define FXOS8700_M_VECM_THS_LSB 0x6b
#define FXOS8700_M_VECM_CNT 0x6c
#define FXOS8700_M_VECM_INITX_MSB 0x6d
#define FXOS8700_M_VECM_INITX_LSB 0x6e
#define FXOS8700_M_VECM_INITY_MSB 0x6f
#define FXOS8700_M_VECM_INITY_LSB 0x70
#define FXOS8700_M_VECM_INITZ_MSB 0x71
#define FXOS8700_M_VECM_INITZ_LSB 0x72
#define FXOS8700_A_FFMT_THS_X_MSB 0x73
#define FXOS8700_A_FFMT_THS_X_LSB 0x74
#define FXOS8700_A_FFMT_THS_Y_MSB 0x75
#define FXOS8700_A_FFMT_THS_Y_LSB 0x76
#define FXOS8700_A_FFMT_THS_Z_MSB 0x77
#define FXOS8700_A_FFMT_THS_Z_LSB 0x78
#define FXOS8700_A_TRAN_INIT_MSB 0x79
#define FXOS8700_A_TRAN_INIT_LSB_X 0x7a
#define FXOS8700_A_TRAN_INIT_LSB_Y 0x7b
#define FXOS8700_A_TRAN_INIT_LSB_Z 0x7d
#define FXOS8700_TM_NVM_LOCK 0x7e
#define FXOS8700_NVM_DATA0_35 0x80
#define FXOS8700_NVM_DATA_BNK3 0xa4
#define FXOS8700_NVM_DATA_BNK2 0xa5
#define FXOS8700_NVM_DATA_BNK1 0xa6
#define FXOS8700_NVM_DATA_BNK0 0xa7
/* Bit definitions for FXOS8700_CTRL_REG1 */
#define FXOS8700_CTRL_ODR_MSK 0x38
#define FXOS8700_CTRL_ODR_MAX 0x00
#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3)
/* Bit definitions for FXOS8700_M_CTRL_REG1 */
#define FXOS8700_HMS_MASK GENMASK(1, 0)
#define FXOS8700_OS_MASK GENMASK(4, 2)
/* Bit definitions for FXOS8700_M_CTRL_REG2 */
#define FXOS8700_MAXMIN_RST BIT(2)
#define FXOS8700_MAXMIN_DIS_THS BIT(3)
#define FXOS8700_MAXMIN_DIS BIT(4)
#define FXOS8700_ACTIVE 0x01
#define FXOS8700_ACTIVE_MIN_USLEEP 4000 /* from table 6 in datasheet */
#define FXOS8700_DEVICE_ID 0xC7
#define FXOS8700_PRE_DEVICE_ID 0xC4
#define FXOS8700_DATA_BUF_SIZE 3
struct fxos8700_data {
struct regmap *regmap;
struct iio_trigger *trig;
__be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned;
};
/* Regmap info */
static const struct regmap_range read_range[] = {
{
.range_min = FXOS8700_STATUS,
.range_max = FXOS8700_A_FFMT_COUNT,
}, {
.range_min = FXOS8700_TRANSIENT_CFG,
.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
},
};
static const struct regmap_range write_range[] = {
{
.range_min = FXOS8700_F_SETUP,
.range_max = FXOS8700_TRIG_CFG,
}, {
.range_min = FXOS8700_XYZ_DATA_CFG,
.range_max = FXOS8700_HP_FILTER_CUTOFF,
}, {
.range_min = FXOS8700_PL_CFG,
.range_max = FXOS8700_A_FFMT_CFG,
}, {
.range_min = FXOS8700_A_FFMT_THS,
.range_max = FXOS8700_TRANSIENT_CFG,
}, {
.range_min = FXOS8700_TRANSIENT_THS,
.range_max = FXOS8700_PULSE_CFG,
}, {
.range_min = FXOS8700_PULSE_THSX,
.range_max = FXOS8700_OFF_Z,
}, {
.range_min = FXOS8700_M_OFF_X_MSB,
.range_max = FXOS8700_M_OFF_Z_LSB,
}, {
.range_min = FXOS8700_M_THS_CFG,
.range_max = FXOS8700_M_THS_CFG,
}, {
.range_min = FXOS8700_M_THS_X_MSB,
.range_max = FXOS8700_M_CTRL_REG3,
}, {
.range_min = FXOS8700_A_VECM_CFG,
.range_max = FXOS8700_A_FFMT_THS_Z_LSB,
},
};
static const struct regmap_access_table driver_read_table = {
.yes_ranges = read_range,
.n_yes_ranges = ARRAY_SIZE(read_range),
};
static const struct regmap_access_table driver_write_table = {
.yes_ranges = write_range,
.n_yes_ranges = ARRAY_SIZE(write_range),
};
const struct regmap_config fxos8700_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = FXOS8700_NVM_DATA_BNK0,
.rd_table = &driver_read_table,
.wr_table = &driver_write_table,
};
EXPORT_SYMBOL(fxos8700_regmap_config);
#define FXOS8700_CHANNEL(_type, _axis) { \
.type = _type, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
enum fxos8700_accel_scale_bits {
MODE_2G = 0,
MODE_4G,
MODE_8G,
};
/* scan indexes follow DATA register order */
enum fxos8700_scan_axis {
FXOS8700_SCAN_ACCEL_X = 0,
FXOS8700_SCAN_ACCEL_Y,
FXOS8700_SCAN_ACCEL_Z,
FXOS8700_SCAN_MAGN_X,
FXOS8700_SCAN_MAGN_Y,
FXOS8700_SCAN_MAGN_Z,
FXOS8700_SCAN_RHALL,
FXOS8700_SCAN_TIMESTAMP,
};
enum fxos8700_sensor {
FXOS8700_ACCEL = 0,
FXOS8700_MAGN,
FXOS8700_NUM_SENSORS /* must be last */
};
enum fxos8700_int_pin {
FXOS8700_PIN_INT1,
FXOS8700_PIN_INT2
};
struct fxos8700_scale {
u8 bits;
int uscale;
};
struct fxos8700_odr {
u8 bits;
int odr;
int uodr;
};
static const struct fxos8700_scale fxos8700_accel_scale[] = {
{ MODE_2G, 244},
{ MODE_4G, 488},
{ MODE_8G, 976},
};
/*
* Accellerometer and magnetometer have the same ODR options, set in the
* CTRL_REG1 register. ODR is halved when using both sensors at once in
* hybrid mode.
*/
static const struct fxos8700_odr fxos8700_odr[] = {
{0x00, 800, 0},
{0x01, 400, 0},
{0x02, 200, 0},
{0x03, 100, 0},
{0x04, 50, 0},
{0x05, 12, 500000},
{0x06, 6, 250000},
{0x07, 1, 562500},
};
static const struct iio_chan_spec fxos8700_channels[] = {
FXOS8700_CHANNEL(IIO_ACCEL, X),
FXOS8700_CHANNEL(IIO_ACCEL, Y),
FXOS8700_CHANNEL(IIO_ACCEL, Z),
FXOS8700_CHANNEL(IIO_MAGN, X),
FXOS8700_CHANNEL(IIO_MAGN, Y),
FXOS8700_CHANNEL(IIO_MAGN, Z),
IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP),
};
static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
{
switch (iio_type) {
case IIO_ACCEL:
return FXOS8700_ACCEL;
case IIO_ANGL_VEL:
return FXOS8700_MAGN;
default:
return -EINVAL;
}
}
static int fxos8700_set_active_mode(struct fxos8700_data *data,
enum fxos8700_sensor t, bool mode)
{
int ret;
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode);
if (ret)
return ret;
usleep_range(FXOS8700_ACTIVE_MIN_USLEEP,
FXOS8700_ACTIVE_MIN_USLEEP + 1000);
return 0;
}
static int fxos8700_set_scale(struct fxos8700_data *data,
enum fxos8700_sensor t, int uscale)
{
int i;
static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
struct device *dev = regmap_get_device(data->regmap);
if (t == FXOS8700_MAGN) {
dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
return -EINVAL;
}
for (i = 0; i < scale_num; i++)
if (fxos8700_accel_scale[i].uscale == uscale)
break;
if (i == scale_num)
return -EINVAL;
return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
fxos8700_accel_scale[i].bits);
}
static int fxos8700_get_scale(struct fxos8700_data *data,
enum fxos8700_sensor t, int *uscale)
{
int i, ret, val;
static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
if (t == FXOS8700_MAGN) {
*uscale = 1200; /* Magnetometer is locked at 1200uT */
return 0;
}
ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);
if (ret)
return ret;
for (i = 0; i < scale_num; i++) {
if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
*uscale = fxos8700_accel_scale[i].uscale;
return 0;
}
}
return -EINVAL;
}
static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
int axis, int *val)
{
u8 base, reg;
int ret;
enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
/* Block read 6 bytes of device output registers to avoid data loss */
ret = regmap_bulk_read(data->regmap, base, data->buf,
FXOS8700_DATA_BUF_SIZE);
if (ret)
return ret;
/* Convert axis to buffer index */
reg = axis - IIO_MOD_X;
/* Convert to native endianness */
*val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
return 0;
}
static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
int odr, int uodr)
{
int i, ret, val;
bool active_mode;
static const int odr_num = ARRAY_SIZE(fxos8700_odr);
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
if (ret)
return ret;
active_mode = val & FXOS8700_ACTIVE;
if (active_mode) {
/*
* The device must be in standby mode to change any of the
* other fields within CTRL_REG1
*/
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
val & ~FXOS8700_ACTIVE);
if (ret)
return ret;
}
for (i = 0; i < odr_num; i++)
if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)
break;
if (i >= odr_num)
return -EINVAL;
return regmap_update_bits(data->regmap,
FXOS8700_CTRL_REG1,
FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
fxos8700_odr[i].bits << 3 | active_mode);
}
static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
int *odr, int *uodr)
{
int i, val, ret;
static const int odr_num = ARRAY_SIZE(fxos8700_odr);
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
if (ret)
return ret;
val &= FXOS8700_CTRL_ODR_MSK;
for (i = 0; i < odr_num; i++)
if (val == fxos8700_odr[i].bits)
break;
if (i >= odr_num)
return -EINVAL;
*odr = fxos8700_odr[i].odr;
*uodr = fxos8700_odr[i].uodr;
return 0;
}
static int fxos8700_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
struct fxos8700_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = fxos8700_get_data(data, chan->type, chan->channel2, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
val2);
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
val, val2);
return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int fxos8700_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct fxos8700_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),
val2);
case IIO_CHAN_INFO_SAMP_FREQ:
return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),
val, val2);
default:
return -EINVAL;
}
}
static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
"1.5625 6.25 12.5 50 100 200 400 800");
static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
"1.5625 6.25 12.5 50 100 200 400 800");
static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
static struct attribute *fxos8700_attrs[] = {
&iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
&iio_const_attr_in_magn_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group fxos8700_attrs_group = {
.attrs = fxos8700_attrs,
};
static const struct iio_info fxos8700_info = {
.read_raw = fxos8700_read_raw,
.write_raw = fxos8700_write_raw,
.attrs = &fxos8700_attrs_group,
};
static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
{
int ret;
unsigned int val;
struct device *dev = regmap_get_device(data->regmap);
ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);
if (ret) {
dev_err(dev, "Error reading chip id\n");
return ret;
}
if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
return -ENODEV;
}
ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);
if (ret)
return ret;
ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);
if (ret)
return ret;
/*
* The device must be in standby mode to change any of the other fields
* within CTRL_REG1
*/
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);
if (ret)
return ret;
/* Set max oversample ratio (OSR) and both devices active */
ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
FXOS8700_HMS_MASK | FXOS8700_OS_MASK);
if (ret)
return ret;
/* Disable and rst min/max measurements & threshold */
ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
FXOS8700_MAXMIN_DIS);
if (ret)
return ret;
/* Max ODR (800Hz individual or 400Hz hybrid), active mode */
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
if (ret)
return ret;
/* Set for max full-scale range (+/-8G) */
return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
}
static void fxos8700_chip_uninit(void *data)
{
struct fxos8700_data *fxos8700_data = data;
fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);
fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);
}
int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi)
{
struct iio_dev *indio_dev;
struct fxos8700_data *data;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
ret = fxos8700_chip_init(data, use_spi);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);
if (ret)
return ret;
indio_dev->dev.parent = dev;
indio_dev->channels = fxos8700_channels;
indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);
indio_dev->name = name ? name : "fxos8700";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &fxos8700_info;
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(fxos8700_core_probe);
MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0
/*
* FXOS8700 - NXP IMU, I2C bits
*
* 7-bit I2C slave address determined by SA1 and SA0 logic level
* inputs represented in the following table:
* SA1 | SA0 | Slave Address
* 0 | 0 | 0x1E
* 0 | 1 | 0x1D
* 1 | 0 | 0x1C
* 1 | 1 | 0x1F
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include "fxos8700.h"
static int fxos8700_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
const char *name = NULL;
regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
if (id)
name = id->name;
return fxos8700_core_probe(&client->dev, regmap, name, false);
}
static const struct i2c_device_id fxos8700_i2c_id[] = {
{"fxos8700", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
static const struct acpi_device_id fxos8700_acpi_match[] = {
{"FXOS8700", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
static const struct of_device_id fxos8700_of_match[] = {
{ .compatible = "nxp,fxos8700" },
{ }
};
MODULE_DEVICE_TABLE(of, fxos8700_of_match);
static struct i2c_driver fxos8700_i2c_driver = {
.driver = {
.name = "fxos8700_i2c",
.acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
.of_match_table = fxos8700_of_match,
},
.probe = fxos8700_i2c_probe,
.id_table = fxos8700_i2c_id,
};
module_i2c_driver(fxos8700_i2c_driver);
MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
MODULE_DESCRIPTION("FXOS8700 I2C driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0
/*
* FXOS8700 - NXP IMU, SPI bits
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "fxos8700.h"
static int fxos8700_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return fxos8700_core_probe(&spi->dev, regmap, id->name, true);
}
static const struct spi_device_id fxos8700_spi_id[] = {
{"fxos8700", 0},
{ }
};
MODULE_DEVICE_TABLE(spi, fxos8700_spi_id);
static const struct acpi_device_id fxos8700_acpi_match[] = {
{"FXOS8700", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
static const struct of_device_id fxos8700_of_match[] = {
{ .compatible = "nxp,fxos8700" },
{ }
};
MODULE_DEVICE_TABLE(of, fxos8700_of_match);
static struct spi_driver fxos8700_spi_driver = {
.probe = fxos8700_spi_probe,
.id_table = fxos8700_spi_id,
.driver = {
.acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
.of_match_table = fxos8700_of_match,
.name = "fxos8700_spi",
},
};
module_spi_driver(fxos8700_spi_driver);
MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
MODULE_DESCRIPTION("FXOS8700 SPI driver");
MODULE_LICENSE("GPL v2");

View File

@ -4,10 +4,11 @@
#
obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o \
inv_mpu_aux.o inv_mpu_magn.o
obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
inv-mpu6050-i2c-objs := inv_mpu_i2c.o inv_mpu_acpi.o
inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
obj-$(CONFIG_INV_MPU6050_SPI) += inv-mpu6050-spi.o
inv-mpu6050-spi-objs := inv_mpu_spi.o
inv-mpu6050-spi-y := inv_mpu_spi.o

View File

@ -0,0 +1,204 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 TDK-InvenSense, Inc.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include "inv_mpu_aux.h"
#include "inv_mpu_iio.h"
/*
* i2c master auxiliary bus transfer function.
* Requires the i2c operations to be correctly setup before.
*/
static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st)
{
/* use 50hz frequency for xfer */
const unsigned int freq = 50;
const unsigned int period_ms = 1000 / freq;
uint8_t d;
unsigned int user_ctrl;
int ret;
/* set sample rate */
d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq);
ret = regmap_write(st->map, st->reg->sample_rate_div, d);
if (ret)
return ret;
/* start i2c master */
user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
if (ret)
goto error_restore_rate;
/* wait for xfer: 1 period + half-period margin */
msleep(period_ms + period_ms / 2);
/* stop i2c master */
user_ctrl = st->chip_config.user_ctrl;
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
if (ret)
goto error_stop_i2c;
/* restore sample rate */
d = st->chip_config.divider;
ret = regmap_write(st->map, st->reg->sample_rate_div, d);
if (ret)
goto error_restore_rate;
return 0;
error_stop_i2c:
regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
error_restore_rate:
regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider);
return ret;
}
/**
* inv_mpu_aux_init() - init i2c auxiliary bus
* @st: driver internal state
*
* Returns 0 on success, a negative error code otherwise.
*/
int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
{
unsigned int val;
int ret;
/* configure i2c master */
val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
INV_MPU6050_BIT_WAIT_FOR_ES;
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val);
if (ret)
return ret;
/* configure i2c master delay */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0);
if (ret)
return ret;
val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN |
INV_MPU6050_BIT_I2C_SLV1_DLY_EN |
INV_MPU6050_BIT_I2C_SLV2_DLY_EN |
INV_MPU6050_BIT_I2C_SLV3_DLY_EN |
INV_MPU6050_BIT_DELAY_ES_SHADOW;
return regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val);
}
/**
* inv_mpu_aux_read() - read register function for i2c auxiliary bus
* @st: driver internal state.
* @addr: chip i2c Address
* @reg: chip register address
* @val: buffer for storing read bytes
* @size: number of bytes to read
*
* Returns 0 on success, a negative error code otherwise.
*/
int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
uint8_t reg, uint8_t *val, size_t size)
{
unsigned int status;
int ret;
if (size > 0x0F)
return -EINVAL;
/* setup i2c SLV0 control: i2c addr, register, enable + size */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
INV_MPU6050_BIT_I2C_SLV_RNW | addr);
if (ret)
return ret;
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
if (ret)
return ret;
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
INV_MPU6050_BIT_SLV_EN | size);
if (ret)
return ret;
/* do i2c xfer */
ret = inv_mpu_i2c_master_xfer(st);
if (ret)
goto error_disable_i2c;
/* disable i2c slave */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
if (ret)
goto error_disable_i2c;
/* check i2c status */
ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
if (ret)
return ret;
if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
return -EIO;
/* read data in registers */
return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
val, size);
error_disable_i2c:
regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
return ret;
}
/**
* inv_mpu_aux_write() - write register function for i2c auxiliary bus
* @st: driver internal state.
* @addr: chip i2c Address
* @reg: chip register address
* @val: 1 byte value to write
*
* Returns 0 on success, a negative error code otherwise.
*/
int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
uint8_t reg, uint8_t val)
{
unsigned int status;
int ret;
/* setup i2c SLV0 control: i2c addr, register, value, enable + size */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr);
if (ret)
return ret;
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
if (ret)
return ret;
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val);
if (ret)
return ret;
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
INV_MPU6050_BIT_SLV_EN | 1);
if (ret)
return ret;
/* do i2c xfer */
ret = inv_mpu_i2c_master_xfer(st);
if (ret)
goto error_disable_i2c;
/* disable i2c slave */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
if (ret)
goto error_disable_i2c;
/* check i2c status */
ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
if (ret)
return ret;
if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
return -EIO;
return 0;
error_disable_i2c:
regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
return ret;
}

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 TDK-InvenSense, Inc.
*/
#ifndef INV_MPU_AUX_H_
#define INV_MPU_AUX_H_
#include "inv_mpu_iio.h"
int inv_mpu_aux_init(const struct inv_mpu6050_state *st);
int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
uint8_t reg, uint8_t *val, size_t size);
int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
uint8_t reg, uint8_t val);
#endif /* INV_MPU_AUX_H_ */

View File

@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include "inv_mpu_iio.h"
#include "inv_mpu_magn.h"
/*
* this is the gyro scale translated from dynamic range plus/minus
@ -103,6 +104,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
.divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE),
.gyro_fifo_enable = false,
.accl_fifo_enable = false,
.magn_fifo_enable = false,
.accl_fs = INV_MPU6050_FS_02G,
.user_ctrl = 0,
};
@ -341,6 +343,11 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
*/
st->chip_period = NSEC_PER_MSEC;
/* magn chip init, noop if not present in the chip */
result = inv_mpu_magn_probe(st);
if (result)
goto error_power_off;
return inv_mpu6050_set_power_itg(st, false);
error_power_off:
@ -420,6 +427,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
IIO_MOD_X, val);
break;
case IIO_MAGN:
ret = inv_mpu_magn_read(st, chan->channel2, val);
break;
default:
ret = -EINVAL;
break;
@ -478,6 +488,8 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
*val2 = INV_MPU6050_TEMP_SCALE;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_MAGN:
return inv_mpu_magn_get_scale(st, chan, val, val2);
default:
return -EINVAL;
}
@ -719,6 +731,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
if (result)
goto fifo_rate_fail_power_off;
/* update rate for magn, noop if not present in chip */
result = inv_mpu_magn_set_rate(st, fifo_rate);
if (result)
goto fifo_rate_fail_power_off;
fifo_rate_fail_power_off:
result |= inv_mpu6050_set_power_itg(st, false);
fifo_rate_fail_unlock:
@ -804,8 +821,14 @@ inv_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct inv_mpu6050_state *data = iio_priv(indio_dev);
const struct iio_mount_matrix *matrix;
return &data->orientation;
if (chan->type == IIO_MAGN)
matrix = &data->magn_orient;
else
matrix = &data->orientation;
return matrix;
}
static const struct iio_chan_spec_ext_info inv_ext_info[] = {
@ -873,6 +896,98 @@ static const unsigned long inv_mpu_scan_masks[] = {
0,
};
#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index) \
{ \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = _chan2, \
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_RAW), \
.scan_index = _index, \
.scan_type = { \
.sign = 's', \
.realbits = _bits, \
.storagebits = 16, \
.shift = 0, \
.endianness = IIO_BE, \
}, \
.ext_info = inv_ext_info, \
}
static const struct iio_chan_spec inv_mpu9250_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
/*
* Note that temperature should only be via polled reading only,
* not the final scan elements output.
*/
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
| BIT(IIO_CHAN_INFO_OFFSET)
| BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1,
},
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
/* Magnetometer resolution is 16 bits */
INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X),
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y),
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z),
};
static const unsigned long inv_mpu9x50_scan_masks[] = {
/* 3-axis accel */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z),
/* 3-axis gyro */
BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z),
/* 3-axis magn */
BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
/* 6-axis accel + gyro */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z),
/* 6-axis accel + magn */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
/* 6-axis gyro + magn */
BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z)
| BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
/* 9-axis accel + gyro + magn */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z)
| BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
0,
};
static const struct iio_chan_spec inv_icm20602_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
{
@ -1034,14 +1149,14 @@ error_power_off:
return result;
}
static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
static int inv_mpu_core_enable_regulator_vddio(struct inv_mpu6050_state *st)
{
int result;
result = regulator_enable(st->vddio_supply);
if (result) {
dev_err(regmap_get_device(st->map),
"Failed to enable regulator: %d\n", result);
"Failed to enable vddio regulator: %d\n", result);
} else {
/* Give the device a little bit of time to start up. */
usleep_range(35000, 70000);
@ -1050,21 +1165,29 @@ static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
return result;
}
static int inv_mpu_core_disable_regulator(struct inv_mpu6050_state *st)
static int inv_mpu_core_disable_regulator_vddio(struct inv_mpu6050_state *st)
{
int result;
result = regulator_disable(st->vddio_supply);
if (result)
dev_err(regmap_get_device(st->map),
"Failed to disable regulator: %d\n", result);
"Failed to disable vddio regulator: %d\n", result);
return result;
}
static void inv_mpu_core_disable_regulator_action(void *_data)
{
inv_mpu_core_disable_regulator(_data);
struct inv_mpu6050_state *st = _data;
int result;
result = regulator_disable(st->vdd_supply);
if (result)
dev_err(regmap_get_device(st->map),
"Failed to disable vdd regulator: %d\n", result);
inv_mpu_core_disable_regulator_vddio(st);
}
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
@ -1133,6 +1256,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return -EINVAL;
}
st->vdd_supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(st->vdd_supply)) {
if (PTR_ERR(st->vdd_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vdd regulator %d\n",
(int)PTR_ERR(st->vdd_supply));
return PTR_ERR(st->vdd_supply);
}
st->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(st->vddio_supply)) {
if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
@ -1142,9 +1274,17 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return PTR_ERR(st->vddio_supply);
}
result = inv_mpu_core_enable_regulator(st);
if (result)
result = regulator_enable(st->vdd_supply);
if (result) {
dev_err(dev, "Failed to enable vdd regulator: %d\n", result);
return result;
}
result = inv_mpu_core_enable_regulator_vddio(st);
if (result) {
regulator_disable(st->vdd_supply);
return result;
}
result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action,
st);
@ -1154,6 +1294,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return result;
}
/* fill magnetometer orientation */
result = inv_mpu_magn_set_orient(st);
if (result)
return result;
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st);
if (result)
@ -1165,9 +1310,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return result;
}
if (inv_mpu_bus_setup)
inv_mpu_bus_setup(indio_dev);
dev_set_drvdata(dev, indio_dev);
indio_dev->dev.parent = dev;
/* name will be NULL when enumerated via ACPI */
@ -1176,14 +1318,37 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
else
indio_dev->name = dev_name(dev);
if (chip_type == INV_ICM20602) {
/* requires parent device set in indio_dev */
if (inv_mpu_bus_setup)
inv_mpu_bus_setup(indio_dev);
switch (chip_type) {
case INV_MPU9250:
case INV_MPU9255:
/*
* Use magnetometer inside the chip only if there is no i2c
* auxiliary device in use.
*/
if (!st->magn_disabled) {
indio_dev->channels = inv_mpu9250_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
} else {
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks;
}
break;
case INV_ICM20602:
indio_dev->channels = inv_icm20602_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
indio_dev->available_scan_masks = inv_icm20602_scan_masks;
} else {
break;
default:
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks;
break;
}
indio_dev->info = &mpu_info;
@ -1221,7 +1386,7 @@ static int inv_mpu_resume(struct device *dev)
int result;
mutex_lock(&st->lock);
result = inv_mpu_core_enable_regulator(st);
result = inv_mpu_core_enable_regulator_vddio(st);
if (result)
goto out_unlock;
@ -1239,7 +1404,7 @@ static int inv_mpu_suspend(struct device *dev)
mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, false);
inv_mpu_core_disable_regulator(st);
inv_mpu_core_disable_regulator_vddio(st);
mutex_unlock(&st->lock);
return result;

View File

@ -68,6 +68,56 @@ static const char *inv_mpu_match_acpi_device(struct device *dev,
return dev_name(dev);
}
static bool inv_mpu_i2c_aux_bus(struct device *dev)
{
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
switch (st->chip_type) {
case INV_ICM20608:
case INV_ICM20602:
/* no i2c auxiliary bus on the chip */
return false;
case INV_MPU9250:
case INV_MPU9255:
if (st->magn_disabled)
return true;
else
return false;
default:
return true;
}
}
/*
* MPU9xxx magnetometer support requires to disable i2c auxiliary bus support.
* To ensure backward compatibility with existing setups, do not disable
* i2c auxiliary bus if it used.
* Check for i2c-gate node in devicetree and set magnetometer disabled.
* Only MPU6500 is supported by ACPI, no need to check.
*/
static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
{
struct inv_mpu6050_state *st = iio_priv(indio_dev);
struct device *dev = indio_dev->dev.parent;
struct device_node *mux_node;
switch (st->chip_type) {
case INV_MPU9250:
case INV_MPU9255:
mux_node = of_get_child_by_name(dev->of_node, "i2c-gate");
if (mux_node != NULL) {
st->magn_disabled = true;
dev_warn(dev, "disable internal use of magnetometer\n");
}
of_node_put(mux_node);
break;
default:
break;
}
return 0;
}
/**
* inv_mpu_probe() - probe function.
* @client: i2c client.
@ -112,17 +162,12 @@ static int inv_mpu_probe(struct i2c_client *client,
}
result = inv_mpu_core_probe(regmap, client->irq, name,
NULL, chip_type);
inv_mpu_magn_disable, chip_type);
if (result < 0)
return result;
st = iio_priv(dev_get_drvdata(&client->dev));
switch (st->chip_type) {
case INV_ICM20608:
case INV_ICM20602:
/* no i2c auxiliary bus on the chip */
break;
default:
if (inv_mpu_i2c_aux_bus(&client->dev)) {
/* declare i2c auxiliary bus */
st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
@ -137,7 +182,6 @@ static int inv_mpu_probe(struct i2c_client *client,
result = inv_mpu_acpi_create_mux_client(client);
if (result)
goto out_del_mux;
break;
}
return 0;

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