mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
Char / Misc / IIO / other driver updates for 6.17-rc1
Here is the big set of char/misc/iio and other smaller driver subsystems for 6.17-rc1. It's a big set this time around, with the huge majority being in the iio subsystem with new drivers and dts files being added there. Highlights include: - IIO driver updates, additions, and changes making more code const and cleaning up some init logic - bus_type constant conversion changes - misc device test functions added - rust miscdevice minor fixup - unused function removals for some drivers - mei driver updates - mhi driver updates - interconnect driver updates - Android binder updates and test infrastructure added - small cdx driver updates - small comedi fixes - small nvmem driver updates - small pps driver updates - some acrn virt driver fixes for printk messages - other small driver updates All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaIeYDg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yk3dwCdF6xoEVZaDkLM5IF3XKWWgdYxjNsAoKUy2kUx YtmVh4S0tMmugfeRGac7 =3Wxi -----END PGP SIGNATURE----- Merge tag 'char-misc-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char / misc / IIO / other driver updates from Greg KH: "Here is the big set of char/misc/iio and other smaller driver subsystems for 6.17-rc1. It's a big set this time around, with the huge majority being in the iio subsystem with new drivers and dts files being added there. Highlights include: - IIO driver updates, additions, and changes making more code const and cleaning up some init logic - bus_type constant conversion changes - misc device test functions added - rust miscdevice minor fixup - unused function removals for some drivers - mei driver updates - mhi driver updates - interconnect driver updates - Android binder updates and test infrastructure added - small cdx driver updates - small comedi fixes - small nvmem driver updates - small pps driver updates - some acrn virt driver fixes for printk messages - other small driver updates All of these have been in linux-next with no reported issues" * tag 'char-misc-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (292 commits) binder: Use seq_buf in binder_alloc kunit tests binder: Add copyright notice to new kunit files misc: ti_fpc202: Switch to of_fwnode_handle() bus: moxtet: Use dev_fwnode() pc104: move PC104 option to drivers/Kconfig drivers: virt: acrn: Don't use %pK through printk comedi: fix race between polling and detaching interconnect: qcom: Add Milos interconnect provider driver dt-bindings: interconnect: document the RPMh Network-On-Chip Interconnect in Qualcomm Milos SoC mei: more prints with client prefix mei: bus: use cldev in prints bus: mhi: host: pci_generic: Add Telit FN990B40 modem support bus: mhi: host: Detect events pointing to unexpected TREs bus: mhi: host: pci_generic: Add Foxconn T99W696 modem bus: mhi: host: Use str_true_false() helper bus: mhi: host: pci_generic: Add support for EM929x and set MRU to 32768 for better performance. bus: mhi: host: Fix endianness of BHI vector table bus: mhi: host: pci_generic: Disable runtime PM for QDU100 bus: mhi: host: pci_generic: Fix the modem name of Foxconn T99W640 dt-bindings: interconnect: qcom,msm8998-bwmon: Allow 'nonposted-mmio' ...
This commit is contained in:
commit
0d5ec7919f
281 changed files with 15268 additions and 2542 deletions
|
@ -48,10 +48,6 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_en
|
|||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY-voltageZ_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en
|
||||
|
@ -73,10 +69,6 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_type
|
|||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_type
|
||||
|
@ -110,10 +102,6 @@ Description:
|
|||
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_z_index
|
||||
|
|
|
@ -141,8 +141,6 @@ Description:
|
|||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_raw
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -417,18 +415,14 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage_q_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage_i_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_q_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_i_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
|
||||
|
@ -456,21 +450,15 @@ Description:
|
|||
to the _raw output.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_i_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_current_q_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
|
||||
|
@ -559,6 +547,30 @@ Description:
|
|||
- a small discrete set of values like "0 2 4 6 8"
|
||||
- a range specified as "[min step max]"
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_convdelay
|
||||
KernelVersion: 6.17
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Delay of start of conversion from common reference point shared
|
||||
by all channels. Can be writable when used to compensate for
|
||||
delay variation introduced by external filters feeding a
|
||||
simultaneous sampling ADC.
|
||||
|
||||
E.g., for the ad7606 ADC series, this value is intended as a
|
||||
configurable time delay in seconds, to correct delay introduced
|
||||
by an optional external filtering circuit.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_convdelay_available
|
||||
KernelVersion: 6.16
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Available values of convdelay. Maybe expressed as:
|
||||
|
||||
- a range specified as "[min step max]"
|
||||
|
||||
If shared across all channels, <type>_convdelay_available
|
||||
is used.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
|
||||
|
@ -579,11 +591,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_calibscale
|
||||
|
@ -805,7 +813,11 @@ Description:
|
|||
all the other channels, since it involves changing the VCO
|
||||
fundamental output frequency.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_i_phase
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltageY_q_phase
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_phase
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_i_phase
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_q_phase
|
||||
KernelVersion: 3.4.0
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -1434,10 +1446,6 @@ What: /sys/.../iio:deviceX/bufferY/in_timestamp_en
|
|||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY-voltageZ_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_i_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_q_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_incli_x_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_incli_y_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_pressureY_en
|
||||
|
@ -1458,10 +1466,6 @@ What: /sys/.../iio:deviceX/bufferY/in_incli_type
|
|||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_i_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_q_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_timestamp_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_pressureY_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_pressure_type
|
||||
|
@ -1499,10 +1503,6 @@ Description:
|
|||
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_supply_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_i_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltageY_q_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_i_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_voltage_q_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_x_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_y_index
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_z_index
|
||||
|
@ -1692,8 +1692,6 @@ Description:
|
|||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_raw
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_raw
|
||||
KernelVersion: 3.17
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
@ -2278,6 +2276,9 @@ Description:
|
|||
Reading returns a list with the possible filter modes. Options
|
||||
for the attribute:
|
||||
|
||||
* "none" - Filter is disabled/bypassed.
|
||||
* "sinc1" - The digital sinc1 filter. Fast 1st
|
||||
conversion time. Poor noise performance.
|
||||
* "sinc3" - The digital sinc3 filter. Moderate 1st
|
||||
conversion time. Good noise performance.
|
||||
* "sinc4" - Sinc 4. Excellent noise performance. Long
|
||||
|
@ -2293,6 +2294,8 @@ Description:
|
|||
* "sinc3+pf2" - Sinc3 + device specific Post Filter 2.
|
||||
* "sinc3+pf3" - Sinc3 + device specific Post Filter 3.
|
||||
* "sinc3+pf4" - Sinc3 + device specific Post Filter 4.
|
||||
* "sinc5+pf1" - Sinc5 + device specific Post Filter 1.
|
||||
* "sinc5+avg" - Sinc5 + averaging by 4.
|
||||
* "wideband" - filter with wideband low ripple passband
|
||||
and sharp transition band.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0-1_i_calibphase
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0-altvoltage1_i_calibphase
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Read/write unscaled value for the Local Oscillatior path quadrature I phase shift.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0-1_q_calibphase
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_altvoltage0-altvoltage1_q_calibphase
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
|
|
96
Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml
Normal file
96
Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml
Normal file
|
@ -0,0 +1,96 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright 2025 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad4080.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD4080 20-Bit, 40 MSPS, Differential SAR ADC
|
||||
|
||||
maintainers:
|
||||
- Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
|
||||
description: |
|
||||
The AD4080 is a high speed, low noise, low distortion, 20-bit, Easy Drive,
|
||||
successive approximation register (SAR) analog-to-digital converter (ADC).
|
||||
Maintaining high performance (signal-to-noise and distortion (SINAD) ratio
|
||||
> 90 dBFS) at signal frequencies in excess of 1 MHz enables the AD4080 to
|
||||
service a wide variety of precision, wide bandwidth data acquisition
|
||||
applications.
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4080.pdf
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad4080
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
description: Configuration of the SPI bus.
|
||||
maximum: 50000000
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: cnv
|
||||
|
||||
vdd33-supply: true
|
||||
|
||||
vdd11-supply: true
|
||||
|
||||
vddldo-supply: true
|
||||
|
||||
iovdd-supply: true
|
||||
|
||||
vrefin-supply: true
|
||||
|
||||
io-backends:
|
||||
maxItems: 1
|
||||
|
||||
adi,lvds-cnv-enable:
|
||||
description: Enable the LVDS signal type on the CNV pin. Default is CMOS.
|
||||
type: boolean
|
||||
|
||||
adi,num-lanes:
|
||||
description:
|
||||
Number of lanes on which the data is sent on the output (DA, DB pins).
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2]
|
||||
default: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- vdd33-supply
|
||||
- vrefin-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad4080";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
vdd33-supply = <&vdd33>;
|
||||
vddldo-supply = <&vddldo>;
|
||||
vrefin-supply = <&vrefin>;
|
||||
clocks = <&cnv>;
|
||||
clock-names = "cnv";
|
||||
io-backends = <&iio_backend>;
|
||||
};
|
||||
};
|
||||
...
|
554
Documentation/devicetree/bindings/iio/adc/adi,ad4170-4.yaml
Normal file
554
Documentation/devicetree/bindings/iio/adc/adi,ad4170-4.yaml
Normal file
|
@ -0,0 +1,554 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad4170-4.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD4170-4 and similar Analog to Digital Converters
|
||||
|
||||
maintainers:
|
||||
- Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices AD4170-4 series of Sigma-delta Analog to Digital Converters.
|
||||
Specifications can be found at:
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4170-4.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4190-4.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad4195-4.pdf
|
||||
|
||||
$ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
$defs:
|
||||
reference-buffer:
|
||||
description: |
|
||||
Enable precharge buffer, full buffer, or skip reference buffering of
|
||||
the positive/negative voltage reference. Because the output impedance
|
||||
of the source driving the voltage reference inputs may be dynamic,
|
||||
resistive/capacitive combinations of those inputs can cause DC gain
|
||||
errors if the reference inputs go unbuffered into the ADC. Enable
|
||||
reference buffering if the provided reference source has dynamic high
|
||||
impedance output. Note the absolute voltage allowed on REFINn+ and REFINn-
|
||||
inputs is from AVSS - 50 mV to AVDD + 50 mV when the reference buffers are
|
||||
disabled but narrows to AVSS to AVDD when reference buffering is enabled
|
||||
or in precharge mode.
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ precharge, full, disabled ]
|
||||
default: full
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad4170-4
|
||||
- adi,ad4190-4
|
||||
- adi,ad4195-4
|
||||
|
||||
avss-supply:
|
||||
description:
|
||||
Reference voltage supply for AVSS. A −2.625V minimum and 0V maximum supply
|
||||
that powers the chip. If not provided, AVSS is assumed to be at system
|
||||
ground (0V).
|
||||
|
||||
avdd-supply:
|
||||
description:
|
||||
A supply of 4.75V to 5.25V relative to AVSS that powers the chip (AVDD).
|
||||
|
||||
iovdd-supply:
|
||||
description: 1.7V to 5.25V reference supply to the serial interface (IOVDD).
|
||||
|
||||
refin1p-supply:
|
||||
description: REFIN+ supply that can be used as reference for conversion.
|
||||
|
||||
refin1n-supply:
|
||||
description: REFIN- supply that can be used as reference for conversion.
|
||||
|
||||
refin2p-supply:
|
||||
description: REFIN2+ supply that can be used as reference for conversion.
|
||||
|
||||
refin2n-supply:
|
||||
description: REFIN2- supply that can be used as reference for conversion.
|
||||
|
||||
spi-cpol: true
|
||||
|
||||
spi-cpha: true
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
Interrupt for signaling the completion of conversion results. The data
|
||||
ready signal (RDY) used as interrupt is by default provided on the SDO
|
||||
pin. Alternatively, it can be provided on the DIG_AUX1 pin in which case
|
||||
the chip disables the RDY function on SDO. Thus, there can be only one
|
||||
data ready interrupt enabled at a time.
|
||||
|
||||
interrupt-names:
|
||||
description:
|
||||
Specify which pin should be configured as Data Ready interrupt.
|
||||
enum:
|
||||
- sdo
|
||||
- dig_aux1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Optional external clock source. Can specify either an external clock or
|
||||
external crystal.
|
||||
|
||||
clock-names:
|
||||
enum:
|
||||
- ext-clk
|
||||
- xtal
|
||||
default: ext-clk
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
description: |
|
||||
The first cell is for the GPIO number: 0 to 3.
|
||||
The second cell takes standard GPIO flags.
|
||||
|
||||
ldac-gpios:
|
||||
description:
|
||||
GPIO connected to DIG_AUX2 pin to be used as LDAC toggle to control the
|
||||
transfer of data from the DAC_INPUT_A register to the DAC.
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
adi,vbias-pins:
|
||||
description: Analog inputs to apply a voltage bias of (AVDD − AVSS) / 2 to.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 1
|
||||
maxItems: 9
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 8
|
||||
|
||||
allOf:
|
||||
# Some devices don't have integrated DAC
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad4190-4
|
||||
- adi,ad4195-4
|
||||
then:
|
||||
properties:
|
||||
ldac-gpios: false
|
||||
|
||||
# Require to specify the interrupt pin when using interrupts
|
||||
- if:
|
||||
required:
|
||||
- interrupts
|
||||
then:
|
||||
required:
|
||||
- interrupt-names
|
||||
|
||||
# If an external clock is set, the internal clock cannot go out and vice versa
|
||||
- oneOf:
|
||||
- required: [clocks]
|
||||
properties:
|
||||
'#clock-cells': false
|
||||
- required: ['#clock-cells']
|
||||
properties:
|
||||
clocks: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- avdd-supply
|
||||
- iovdd-supply
|
||||
- spi-cpol
|
||||
- spi-cpha
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]$":
|
||||
$ref: /schemas/iio/adc/adc.yaml#
|
||||
unevaluatedProperties: false
|
||||
description:
|
||||
Represents the external channels which are connected to the ADC.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
The channel number.
|
||||
minimum: 0
|
||||
maximum: 15
|
||||
|
||||
diff-channels:
|
||||
description: |
|
||||
This property is used for defining the inputs of a differential
|
||||
voltage channel. The first value is the positive input and the second
|
||||
value is the negative input of the channel.
|
||||
|
||||
Besides the analog input pins AIN0 to AIN8, there are special inputs
|
||||
that can be selected with the following values:
|
||||
17: Internal temperature sensor
|
||||
18: (AVDD-AVSS)/5
|
||||
19: (IOVDD-DGND)/5
|
||||
20: DAC output
|
||||
21: ALDO
|
||||
22: DLDO
|
||||
23: AVSS
|
||||
24: DGND
|
||||
25: REFIN+
|
||||
26: REFIN-
|
||||
27: REFIN2+
|
||||
28: REFIN2-
|
||||
29: REFOUT
|
||||
For the internal temperature sensor, use the input number for both
|
||||
inputs (i.e. diff-channels = <17 17>).
|
||||
items:
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7, 8, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
26, 27, 28, 29]
|
||||
|
||||
adi,reference-select:
|
||||
description: |
|
||||
Select the reference source to use when converting on the
|
||||
specific channel. Valid values are:
|
||||
0: REFIN+/REFIN-
|
||||
1: REFIN2+/REFIN2−
|
||||
2: REFOUT/AVSS (internal reference)
|
||||
3: AVDD/AVSS
|
||||
If not specified, REFOUT/AVSS is used.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3]
|
||||
default: 1
|
||||
|
||||
adi,positive-reference-buffer:
|
||||
$ref: '#/$defs/reference-buffer'
|
||||
|
||||
adi,negative-reference-buffer:
|
||||
$ref: '#/$defs/reference-buffer'
|
||||
|
||||
adi,sensor-type:
|
||||
description:
|
||||
The AD4170-4 and similar designs have features to aid interfacing with
|
||||
load cell weigh scale, RTD, and thermocouple sensors. Each of those
|
||||
sensor types requires either distinct wiring configuration or
|
||||
external circuitry for proper sensor operation and can use different
|
||||
ADC chip functionality on their setups. A key characteristic of those
|
||||
external sensors is that they must be excited either by voltage supply
|
||||
or by ADC chip excitation signals. The sensor can then be read through
|
||||
a pair of analog inputs. This property specifies which particular
|
||||
sensor type is connected to the ADC so it can be properly setup and
|
||||
handled. Omit this property for conventional (not weigh scale, RTD, or
|
||||
thermocouple) ADC channel setups.
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
enum: [ weighscale, rtd, thermocouple ]
|
||||
|
||||
adi,excitation-pin-0:
|
||||
description:
|
||||
Analog input to apply excitation current to while the channel
|
||||
is active.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 20
|
||||
default: 0
|
||||
|
||||
adi,excitation-pin-1:
|
||||
description:
|
||||
Analog input to apply excitation current to while the channel
|
||||
is active.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 20
|
||||
default: 0
|
||||
|
||||
adi,excitation-pin-2:
|
||||
description:
|
||||
Analog input to apply excitation current to while the channel
|
||||
is active.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 20
|
||||
default: 0
|
||||
|
||||
adi,excitation-pin-3:
|
||||
description:
|
||||
Analog input to apply excitation current to while the channel
|
||||
is active.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 20
|
||||
default: 0
|
||||
|
||||
adi,excitation-current-0-microamp:
|
||||
description:
|
||||
Excitation current in microamperes to be applied to pin specified in
|
||||
adi,excitation-pin-0 while this channel is active.
|
||||
enum: [0, 10, 50, 100, 250, 500, 1000, 1500]
|
||||
default: 0
|
||||
|
||||
adi,excitation-current-1-microamp:
|
||||
description:
|
||||
Excitation current in microamperes to be applied to pin specified in
|
||||
adi,excitation-pin-1 while this channel is active.
|
||||
enum: [0, 10, 50, 100, 250, 500, 1000, 1500]
|
||||
default: 0
|
||||
|
||||
adi,excitation-current-2-microamp:
|
||||
description:
|
||||
Excitation current in microamperes to be applied to pin specified in
|
||||
adi,excitation-pin-2 while this channel is active.
|
||||
enum: [0, 10, 50, 100, 250, 500, 1000, 1500]
|
||||
default: 0
|
||||
|
||||
adi,excitation-current-3-microamp:
|
||||
description:
|
||||
Excitation current in microamperes to be applied to pin specified in
|
||||
adi,excitation-pin-3 while this channel is active.
|
||||
enum: [0, 10, 50, 100, 250, 500, 1000, 1500]
|
||||
default: 0
|
||||
|
||||
adi,excitation-ac:
|
||||
type: boolean
|
||||
description:
|
||||
Whether the external sensor has to be AC or DC excited. When omitted,
|
||||
it is DC excited.
|
||||
|
||||
allOf:
|
||||
- oneOf:
|
||||
- required: [single-channel, common-mode-channel]
|
||||
properties:
|
||||
diff-channels: false
|
||||
- required: [diff-channels]
|
||||
properties:
|
||||
single-channel: false
|
||||
common-mode-channel: false
|
||||
# Usual ADC channels don't need external circuitry excitation.
|
||||
- if:
|
||||
not:
|
||||
required:
|
||||
- adi,sensor-type
|
||||
then:
|
||||
properties:
|
||||
adi,excitation-pin-0: false
|
||||
adi,excitation-pin-1: false
|
||||
adi,excitation-pin-2: false
|
||||
adi,excitation-pin-3: false
|
||||
adi,excitation-current-0-microamp: false
|
||||
adi,excitation-current-1-microamp: false
|
||||
adi,excitation-current-2-microamp: false
|
||||
adi,excitation-current-3-microamp: false
|
||||
adi,excitation-ac: false
|
||||
# Weigh scale bridge AC excited with one pair of predefined signals.
|
||||
- if:
|
||||
allOf:
|
||||
- properties:
|
||||
adi,sensor-type:
|
||||
contains:
|
||||
const: weighscale
|
||||
- required:
|
||||
- adi,excitation-ac
|
||||
- adi,excitation-pin-2
|
||||
- adi,excitation-pin-3
|
||||
- not:
|
||||
required:
|
||||
- adi,excitation-current-2-microamp
|
||||
- adi,excitation-current-3-microamp
|
||||
then:
|
||||
properties:
|
||||
adi,excitation-pin-2:
|
||||
const: 19
|
||||
adi,excitation-pin-3:
|
||||
const: 20
|
||||
# Weigh scale bridge AC excited with two pairs of predefined signals.
|
||||
- if:
|
||||
allOf:
|
||||
- properties:
|
||||
adi,sensor-type:
|
||||
contains:
|
||||
const: weighscale
|
||||
- required:
|
||||
- adi,excitation-ac
|
||||
- adi,excitation-pin-0
|
||||
- adi,excitation-pin-1
|
||||
- adi,excitation-pin-2
|
||||
- adi,excitation-pin-3
|
||||
- not:
|
||||
required:
|
||||
- adi,excitation-current-0-microamp
|
||||
- adi,excitation-current-1-microamp
|
||||
- adi,excitation-current-2-microamp
|
||||
- adi,excitation-current-3-microamp
|
||||
then:
|
||||
properties:
|
||||
adi,excitation-pin-0:
|
||||
const: 17
|
||||
adi,excitation-pin-1:
|
||||
const: 18
|
||||
adi,excitation-pin-2:
|
||||
const: 19
|
||||
adi,excitation-pin-3:
|
||||
const: 20
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad4170-4";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <20000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
avdd-supply = <&avdd>;
|
||||
iovdd-supply = <&iovdd>;
|
||||
clocks = <&clk>;
|
||||
clock-names = "xtal";
|
||||
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-names = "dig_aux1";
|
||||
adi,vbias-pins = <8>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
// Sample AIN0 with respect to DGND throughout AVDD/DGND input range
|
||||
// Pseudo-differential unipolar
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
single-channel = <0>;
|
||||
common-mode-channel = <24>;
|
||||
adi,reference-select = <3>;
|
||||
};
|
||||
// Weigh scale sensor
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
bipolar;
|
||||
diff-channels = <1 2>;
|
||||
adi,reference-select = <0>;
|
||||
adi,positive-reference-buffer = "precharge";
|
||||
adi,negative-reference-buffer = "precharge";
|
||||
adi,sensor-type = "weighscale";
|
||||
adi,excitation-pin-2 = <19>;
|
||||
adi,excitation-pin-3 = <20>;
|
||||
adi,excitation-ac;
|
||||
};
|
||||
// RTD sensor
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
bipolar;
|
||||
diff-channels = <3 4>;
|
||||
adi,reference-select = <0>;
|
||||
adi,sensor-type = "rtd";
|
||||
adi,excitation-pin-0 = <5>;
|
||||
adi,excitation-pin-1 = <6>;
|
||||
adi,excitation-current-0-microamp = <500>;
|
||||
adi,excitation-current-1-microamp = <500>;
|
||||
adi,excitation-ac;
|
||||
};
|
||||
// Thermocouple sensor
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
bipolar;
|
||||
diff-channels = <7 8>;
|
||||
adi,reference-select = <0>;
|
||||
adi,sensor-type = "thermocouple";
|
||||
adi,excitation-pin-0 = <18>;
|
||||
adi,excitation-current-0-microamp = <500>;
|
||||
};
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad4170-4";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <20000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
avdd-supply = <&avdd>;
|
||||
iovdd-supply = <&iovdd>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "ad4170-clk16mhz";
|
||||
interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-names = "dig_aux1";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
// Sample AIN0 with respect to AIN1 throughout AVDD/AVSS input range
|
||||
// Differential bipolar. If AVSS < 0V, differential true bipolar
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
bipolar;
|
||||
diff-channels = <0 1>;
|
||||
adi,reference-select = <3>;
|
||||
};
|
||||
// Sample AIN2 with respect to DGND throughout AVDD/DGND input range
|
||||
// Pseudo-differential unipolar
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
single-channel = <2>;
|
||||
common-mode-channel = <24>;
|
||||
adi,reference-select = <3>;
|
||||
};
|
||||
// Sample AIN3 with respect to 2.5V throughout AVDD/AVSS input range
|
||||
// Pseudo-differential bipolar
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
bipolar;
|
||||
single-channel = <3>;
|
||||
common-mode-channel = <29>;
|
||||
adi,reference-select = <3>;
|
||||
};
|
||||
// Sample AIN4 with respect to DGND throughout AVDD/AVSS input range
|
||||
// Pseudo-differential bipolar
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
bipolar;
|
||||
single-channel = <4>;
|
||||
common-mode-channel = <24>;
|
||||
adi,reference-select = <3>;
|
||||
};
|
||||
// Sample AIN5 with respect to 2.5V throughout AVDD/AVSS input range
|
||||
// Pseudo-differential unipolar (AD4170-4 datasheet page 46 example)
|
||||
channel@4 {
|
||||
reg = <4>;
|
||||
single-channel = <5>;
|
||||
common-mode-channel = <29>;
|
||||
adi,reference-select = <3>;
|
||||
};
|
||||
// Sample AIN6 with respect to 2.5V throughout REFIN+/REFIN- input range
|
||||
// Pseudo-differential bipolar
|
||||
channel@5 {
|
||||
reg = <5>;
|
||||
bipolar;
|
||||
single-channel = <6>;
|
||||
common-mode-channel = <29>;
|
||||
adi,reference-select = <0>;
|
||||
};
|
||||
// Weigh scale sensor
|
||||
channel@6 {
|
||||
reg = <6>;
|
||||
bipolar;
|
||||
diff-channels = <7 8>;
|
||||
adi,reference-select = <0>;
|
||||
adi,sensor-type = "weighscale";
|
||||
adi,excitation-pin-0 = <17>;
|
||||
adi,excitation-pin-1 = <18>;
|
||||
adi,excitation-pin-2 = <19>;
|
||||
adi,excitation-pin-3 = <20>;
|
||||
adi,excitation-ac;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
|
@ -69,6 +69,8 @@ properties:
|
|||
spi-max-frequency:
|
||||
maximum: 25000000
|
||||
|
||||
spi-3wire: true
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
|
|
60
Documentation/devicetree/bindings/iio/adc/adi,ad7405.yaml
Normal file
60
Documentation/devicetree/bindings/iio/adc/adi,ad7405.yaml
Normal file
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright 2025 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad7405.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD7405 family
|
||||
|
||||
maintainers:
|
||||
- Dragos Bogdan <dragos.bogdan@analog.com>
|
||||
- Pop Ioan Daniel <pop.ioan-daniel@analog.com>
|
||||
|
||||
description: |
|
||||
Analog Devices AD7405 is a high performance isolated ADC, 1-channel,
|
||||
16-bit with a second-order Σ-Δ modulator that converts an analog input signal
|
||||
into a high speed, single-bit data stream.
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7405.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/adum7701.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/adum7702.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ADuM7703.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad7405
|
||||
- adi,adum7701
|
||||
- adi,adum7702
|
||||
- adi,adum7703
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
vdd1-supply: true
|
||||
|
||||
vdd2-supply: true
|
||||
|
||||
io-backends:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- vdd1-supply
|
||||
- vdd2-supply
|
||||
- io-backends
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
adc {
|
||||
compatible = "adi,ad7405";
|
||||
clocks = <&axi_clk_gen 0>;
|
||||
vdd1-supply = <&vdd1>;
|
||||
vdd2-supply = <&vdd2>;
|
||||
io-backends = <&axi_adc>;
|
||||
};
|
||||
...
|
|
@ -204,6 +204,15 @@ patternProperties:
|
|||
considered a bipolar differential channel. Otherwise it is bipolar
|
||||
single-ended.
|
||||
|
||||
adi,rfilter-ohms:
|
||||
description:
|
||||
For ADCs that supports gain calibration, this property must be set to
|
||||
the value of the external RFilter resistor. Proper gain error
|
||||
correction is applied based on this value.
|
||||
default: 0
|
||||
minimum: 0
|
||||
maximum: 64512
|
||||
|
||||
required:
|
||||
- reg
|
||||
- bipolar
|
||||
|
@ -250,6 +259,25 @@ allOf:
|
|||
properties:
|
||||
adi,oversampling-ratio-gpios: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7605-4
|
||||
- adi,ad7606-4
|
||||
- adi,ad7606-6
|
||||
- adi,ad7606-8
|
||||
- adi,ad7607
|
||||
- adi,ad7608
|
||||
- adi,ad7609
|
||||
- adi,ad7616
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel@[0-9a-f]+$":
|
||||
properties:
|
||||
adi,rfilter-ohms: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -392,6 +420,7 @@ examples:
|
|||
reg = <8>;
|
||||
diff-channels = <8 8>;
|
||||
bipolar;
|
||||
adi,rfilter-ohms = <2048>;
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -26,7 +26,26 @@ properties:
|
|||
clock-names:
|
||||
const: mclk
|
||||
|
||||
trigger-sources:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
A list of phandles referencing trigger source providers. Each entry
|
||||
represents a trigger source for the ADC:
|
||||
|
||||
- First entry specifies the device responsible for driving the
|
||||
synchronization (SYNC_IN) pin, as an alternative to adi,sync-in-gpios.
|
||||
This can be a `gpio-trigger` or another `ad7768-1` device. If the
|
||||
device's own SYNC_OUT pin is internally connected to its SYNC_IN pin,
|
||||
reference the device itself or omit this property.
|
||||
- Second entry optionally defines a GPIO3 pin used as a START signal trigger.
|
||||
|
||||
Use the accompanying trigger source cell to identify the type of each entry.
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
DRDY (Data Ready) pin, which signals conversion results are available.
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
|
@ -47,6 +66,19 @@ properties:
|
|||
in any way, for example if the filter decimation rate changes.
|
||||
As the line is active low, it should be marked GPIO_ACTIVE_LOW.
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
description:
|
||||
list of regulators provided by this controller.
|
||||
|
||||
properties:
|
||||
vcm-output:
|
||||
$ref: /schemas/regulator/regulator.yaml#
|
||||
type: object
|
||||
unevaluatedProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -57,6 +89,23 @@ properties:
|
|||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
"#trigger-source-cells":
|
||||
description: |
|
||||
Cell indicates the trigger output signal: 0 = SYNC_OUT, 1 = GPIO3,
|
||||
2 = DRDY.
|
||||
|
||||
For better readability, macros for these values are available in
|
||||
dt-bindings/iio/adc/adi,ad7768-1.h.
|
||||
const: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
description: |
|
||||
The first cell is for the GPIO number: 0 to 3.
|
||||
The second cell takes standard GPIO flags.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -65,7 +114,16 @@ required:
|
|||
- vref-supply
|
||||
- spi-cpol
|
||||
- spi-cpha
|
||||
- adi,sync-in-gpios
|
||||
|
||||
dependencies:
|
||||
adi,sync-in-gpios:
|
||||
not:
|
||||
required:
|
||||
- trigger-sources
|
||||
trigger-sources:
|
||||
not:
|
||||
required:
|
||||
- adi,sync-in-gpios
|
||||
|
||||
patternProperties:
|
||||
"^channel@([0-9]|1[0-5])$":
|
||||
|
@ -105,6 +163,8 @@ examples:
|
|||
spi-max-frequency = <2000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
vref-supply = <&adc_vref>;
|
||||
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-parent = <&gpio>;
|
||||
|
@ -120,6 +180,12 @@ examples:
|
|||
reg = <0>;
|
||||
label = "channel_0";
|
||||
};
|
||||
|
||||
regulators {
|
||||
vcm_reg: vcm-output {
|
||||
regulator-name = "ad7768-1-vcm";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
@ -27,6 +27,7 @@ description: |
|
|||
the ad7606 family.
|
||||
|
||||
https://wiki.analog.com/resources/fpga/docs/axi_adc_ip
|
||||
https://analogdevicesinc.github.io/hdl/library/axi_ad408x/index.html
|
||||
https://analogdevicesinc.github.io/hdl/library/axi_ad485x/index.html
|
||||
http://analogdevicesinc.github.io/hdl/library/axi_ad7606x/index.html
|
||||
|
||||
|
@ -34,6 +35,7 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- adi,axi-adc-10.0.a
|
||||
- adi,axi-ad408x
|
||||
- adi,axi-ad7606x
|
||||
- adi,axi-ad485x
|
||||
|
||||
|
|
|
@ -32,6 +32,10 @@ properties:
|
|||
- enum:
|
||||
- mediatek,mt7623-auxadc
|
||||
- const: mediatek,mt2701-auxadc
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt7981-auxadc
|
||||
- const: mediatek,mt7986-auxadc
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt6893-auxadc
|
||||
|
|
|
@ -22,6 +22,8 @@ properties:
|
|||
- mediatek,mt6357-auxadc
|
||||
- mediatek,mt6358-auxadc
|
||||
- mediatek,mt6359-auxadc
|
||||
- mediatek,mt6363-auxadc
|
||||
- mediatek,mt6373-auxadc
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
|
|
@ -22,6 +22,9 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
vref-supply: true
|
||||
|
||||
"#io-channel-cells":
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/st,spear600-adc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ST SPEAr ADC device driver
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description: |
|
||||
Integrated ADC inside the ST SPEAr SoC, SPEAr600, supporting
|
||||
10-bit resolution. Datasheet can be found here:
|
||||
https://www.st.com/resource/en/datasheet/spear600.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- st,spear600-adc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
sampling-frequency:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 2500000
|
||||
maximum: 20000000
|
||||
description:
|
||||
Default sampling frequency of the ADC in Hz.
|
||||
|
||||
vref-external:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1000
|
||||
maximum: 2800
|
||||
description:
|
||||
External voltage reference in milli-volts. If omitted the internal voltage
|
||||
reference will be used.
|
||||
|
||||
average-samples:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 15
|
||||
default: 0
|
||||
description:
|
||||
Number of samples to generate an average value. If omitted, single data
|
||||
conversion will be used.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- sampling-frequency
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
adc@d8200000 {
|
||||
compatible = "st,spear600-adc";
|
||||
reg = <0xd8200000 0x1000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <6>;
|
||||
sampling-frequency = <5000000>;
|
||||
vref-external = <2500>; /* 2.5V VRef */
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/gyroscope/invensense,itg3200.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Invensense ITG-3200 Gyroscope
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description: |
|
||||
Triple-axis, digital output gyroscope with a three 16-bit analog-to-digital
|
||||
converters (ADCs) for digitizing the gyro outputs, a user-selectable internal
|
||||
low-pass filter bandwidth, and a Fast-Mode I2C.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: invensense,itg3200
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
vlogic-supply: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
mount-matrix:
|
||||
description: an optional 3x3 mounting rotation matrix.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ext_clock
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
gyroscope@68 {
|
||||
compatible = "invensense,itg3200";
|
||||
reg = <0x68>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <24 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/proximity/nicera,d3323aa.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Nicera D3-323-AA PIR sensor
|
||||
|
||||
maintainers:
|
||||
- Waqar Hameed <waqar.hameed@axis.com>
|
||||
|
||||
description: |
|
||||
PIR sensor for human detection.
|
||||
Datasheet: https://www.endrich.com/Datenbl%C3%A4tter/Sensoren/D3-323-AA_e.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nicera,d3323aa
|
||||
|
||||
vdd-supply:
|
||||
description:
|
||||
Supply voltage (1.8 to 5.5 V).
|
||||
|
||||
vout-clk-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
GPIO for clock and detection.
|
||||
After reset, the device signals with two falling edges on this pin that it
|
||||
is ready for configuration (within 1.2 s).
|
||||
During configuration, it is used as clock for data reading and writing (on
|
||||
data-gpios).
|
||||
After all this, when device is in operational mode, it signals on this pin
|
||||
for any detections.
|
||||
|
||||
data-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
GPIO for data reading and writing. This is denoted "DO (SI)" in datasheet.
|
||||
During configuration, this pin is used for writing and reading
|
||||
configuration data (together with vout-clk-gpios as clock).
|
||||
After this, during operational mode, the device will output serial data on
|
||||
this GPIO.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- vdd-supply
|
||||
- vout-clk-gpios
|
||||
- data-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
proximity {
|
||||
compatible = "nicera,d3323aa";
|
||||
vdd-supply = <®ulator_3v3>;
|
||||
vout-clk-gpios = <&gpio 78 GPIO_ACTIVE_HIGH>;
|
||||
data-gpios = <&gpio 76 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
...
|
|
@ -0,0 +1,136 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/interconnect/qcom,milos-rpmh.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm RPMh Network-On-Chip Interconnect on Milos SoC
|
||||
|
||||
maintainers:
|
||||
- Luca Weiss <luca.weiss@fairphone.com>
|
||||
|
||||
description: |
|
||||
RPMh interconnect providers support system bandwidth requirements through
|
||||
RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is
|
||||
able to communicate with the BCM through the Resource State Coordinator (RSC)
|
||||
associated with each execution environment. Provider nodes must point to at
|
||||
least one RPMh device child node pertaining to their RSC and each provider
|
||||
can map to multiple RPMh resources.
|
||||
|
||||
See also: include/dt-bindings/interconnect/qcom,milos-rpmh.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,milos-aggre1-noc
|
||||
- qcom,milos-aggre2-noc
|
||||
- qcom,milos-clk-virt
|
||||
- qcom,milos-cnoc-cfg
|
||||
- qcom,milos-cnoc-main
|
||||
- qcom,milos-gem-noc
|
||||
- qcom,milos-lpass-ag-noc
|
||||
- qcom,milos-mc-virt
|
||||
- qcom,milos-mmss-noc
|
||||
- qcom,milos-nsp-noc
|
||||
- qcom,milos-pcie-anoc
|
||||
- qcom,milos-system-noc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,rpmh-common.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-clk-virt
|
||||
- qcom,milos-mc-virt
|
||||
then:
|
||||
properties:
|
||||
reg: false
|
||||
else:
|
||||
required:
|
||||
- reg
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-pcie-anoc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: aggre-NOC PCIe AXI clock
|
||||
- description: cfg-NOC PCIe a-NOC AHB clock
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-aggre1-noc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: aggre USB3 PRIM AXI clock
|
||||
- description: aggre UFS PHY AXI clock
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-aggre2-noc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: RPMH CC IPA clock
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,milos-aggre1-noc
|
||||
- qcom,milos-aggre2-noc
|
||||
- qcom,milos-pcie-anoc
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
else:
|
||||
properties:
|
||||
clocks: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,milos-gcc.h>
|
||||
|
||||
interconnect-0 {
|
||||
compatible = "qcom,milos-clk-virt";
|
||||
#interconnect-cells = <2>;
|
||||
qcom,bcm-voters = <&apps_bcm_voter>;
|
||||
};
|
||||
|
||||
interconnect@16e0000 {
|
||||
compatible = "qcom,milos-aggre1-noc";
|
||||
reg = <0x016e0000 0x16400>;
|
||||
#interconnect-cells = <2>;
|
||||
clocks = <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
|
||||
<&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>;
|
||||
qcom,bcm-voters = <&apps_bcm_voter>;
|
||||
};
|
|
@ -76,6 +76,8 @@ properties:
|
|||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
nonposted-mmio: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interconnects
|
||||
|
|
|
@ -36,6 +36,11 @@ properties:
|
|||
- qcom,sm8350-epss-l3
|
||||
- qcom,sm8650-epss-l3
|
||||
- const: qcom,epss-l3
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,qcs8300-epss-l3
|
||||
- const: qcom,sa8775p-epss-l3
|
||||
- const: qcom,epss-l3
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -13,7 +13,7 @@ description: |
|
|||
RPMh interconnect providers support system bandwidth requirements through
|
||||
RPMh hardware accelerators known as Bus Clock Manager (BCM).
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sa8775p.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sa8775p.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -18,7 +18,7 @@ description: |
|
|||
least one RPMh device child node pertaining to their RSC and each provider
|
||||
can map to multiple RPMh resources.
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sar2130p-rpmh.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sar2130p-rpmh.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -14,7 +14,7 @@ description: |
|
|||
RPMh interconnect providers support system bandwidth requirements through
|
||||
RPMh hardware accelerators known as Bus Clock Manager (BCM).
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sc7280.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sc7280.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -14,7 +14,7 @@ description: |
|
|||
RPMh interconnect providers support system bandwidth requirements through
|
||||
RPMh hardware accelerators known as Bus Clock Manager (BCM).
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sc8280xp.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sc8280xp.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -13,7 +13,7 @@ description: |
|
|||
RPMh interconnect providers support system bandwidth requirements through
|
||||
RPMh hardware accelerators known as Bus Clock Manager (BCM).
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sm7150-rpmh.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sm7150-rpmh.h
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,rpmh-common.yaml#
|
||||
|
|
|
@ -14,7 +14,7 @@ description: |
|
|||
RPMh interconnect providers support system bandwidth requirements through
|
||||
RPMh hardware accelerators known as Bus Clock Manager (BCM).
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sm8450.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sm8450.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -18,7 +18,7 @@ description: |
|
|||
least one RPMh device child node pertaining to their RSC and each provider
|
||||
can map to multiple RPMh resources.
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sm8550-rpmh.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sm8550-rpmh.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -18,7 +18,7 @@ description: |
|
|||
least one RPMh device child node pertaining to their RSC and each provider
|
||||
can map to multiple RPMh resources.
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sm8650-rpmh.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sm8650-rpmh.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -18,7 +18,7 @@ description: |
|
|||
least one RPMh device child node pertaining to their RSC and each provider
|
||||
can map to multiple RPMh resources.
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,sm8750-rpmh.h
|
||||
See also: include/dt-bindings/interconnect/qcom,sm8750-rpmh.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -18,7 +18,7 @@ description: |
|
|||
least one RPMh device child node pertaining to their RSC and each provider
|
||||
can map to multiple RPMh resources.
|
||||
|
||||
See also:: include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h
|
||||
See also: include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
|
|
@ -27,6 +27,7 @@ properties:
|
|||
- enum:
|
||||
- allwinner,sun50i-a100-sid
|
||||
- allwinner,sun50i-h616-sid
|
||||
- allwinner,sun55i-a523-sid
|
||||
- const: allwinner,sun50i-a64-sid
|
||||
- const: allwinner,sun50i-h5-sid
|
||||
- const: allwinner,sun50i-h6-sid
|
||||
|
|
47
Documentation/devicetree/bindings/nvmem/fsl,vf610-ocotp.yaml
Normal file
47
Documentation/devicetree/bindings/nvmem/fsl,vf610-ocotp.yaml
Normal file
|
@ -0,0 +1,47 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/nvmem/fsl,vf610-ocotp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: On-Chip OTP Memory for Freescale Vybrid
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
allOf:
|
||||
- $ref: nvmem.yaml#
|
||||
- $ref: nvmem-deprecated-cells.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- fsl,vf610-ocotp
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: ipg clock we associate with the OCOTP peripheral
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/vf610-clock.h>
|
||||
|
||||
ocotp@400a5000 {
|
||||
compatible = "fsl,vf610-ocotp", "syscon";
|
||||
reg = <0x400a5000 0xcf0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
clocks = <&clks VF610_CLK_OCOTP>;
|
||||
};
|
|
@ -27,7 +27,7 @@ properties:
|
|||
const: 1
|
||||
|
||||
patternProperties:
|
||||
"@[a-f0-9]+$":
|
||||
"@[a-f0-9]+(,[0-7])?$":
|
||||
type: object
|
||||
$ref: fixed-cell.yaml
|
||||
unevaluatedProperties: false
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
* NXP LPC18xx EEPROM memory NVMEM driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nxp,lpc1857-eeprom"
|
||||
- reg: Must contain an entry with the physical base address and length
|
||||
for each entry in reg-names.
|
||||
- reg-names: Must include the following entries.
|
||||
- reg: EEPROM registers.
|
||||
- mem: EEPROM address space.
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
- clock-names: Must include the following entries.
|
||||
- eeprom: EEPROM operating clock.
|
||||
- resets: Should contain a reference to the reset controller asserting
|
||||
the EEPROM in reset.
|
||||
- interrupts: Should contain EEPROM interrupt.
|
||||
|
||||
Example:
|
||||
|
||||
eeprom: eeprom@4000e000 {
|
||||
compatible = "nxp,lpc1857-eeprom";
|
||||
reg = <0x4000e000 0x1000>,
|
||||
<0x20040000 0x4000>;
|
||||
reg-names = "reg", "mem";
|
||||
clocks = <&ccu1 CLK_CPU_EEPROM>;
|
||||
clock-names = "eeprom";
|
||||
resets = <&rgu 27>;
|
||||
interrupts = <4>;
|
||||
};
|
|
@ -24,6 +24,21 @@ properties:
|
|||
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: mediatek,mt8188-efuse
|
||||
- const: mediatek,mt8186-efuse
|
||||
- const: mediatek,mt8186-efuse
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt8186-efuse
|
||||
- mediatek,mt8188-efuse
|
||||
- const: mediatek,efuse
|
||||
deprecated: true
|
||||
description: Some compatibles also imply a decoding scheme for the
|
||||
"gpu-speedbin" cell, and thus are not backward compatible to the
|
||||
generic "mediatek,efuse" compatible.
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt7622-efuse
|
||||
|
@ -33,8 +48,6 @@ properties:
|
|||
- mediatek,mt7988-efuse
|
||||
- mediatek,mt8173-efuse
|
||||
- mediatek,mt8183-efuse
|
||||
- mediatek,mt8186-efuse
|
||||
- mediatek,mt8188-efuse
|
||||
- mediatek,mt8192-efuse
|
||||
- mediatek,mt8195-efuse
|
||||
- mediatek,mt8516-efuse
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/nvmem/nxp,lpc1857-eeprom.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP LPC18xx EEPROM memory
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,lpc1857-eeprom
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: reg
|
||||
- const: mem
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: eeprom
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/lpc18xx-ccu.h>
|
||||
|
||||
eeprom@4000e000 {
|
||||
compatible = "nxp,lpc1857-eeprom";
|
||||
reg = <0x4000e000 0x1000>,
|
||||
<0x20040000 0x4000>;
|
||||
reg-names = "reg", "mem";
|
||||
clocks = <&ccu1 CLK_CPU_EEPROM>;
|
||||
clock-names = "eeprom";
|
||||
resets = <&rgu 27>;
|
||||
interrupts = <4>;
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
On-Chip OTP Memory for Freescale Vybrid
|
||||
|
||||
Required Properties:
|
||||
compatible:
|
||||
- "fsl,vf610-ocotp", "syscon" for VF5xx/VF6xx
|
||||
#address-cells : Should be 1
|
||||
#size-cells : Should be 1
|
||||
reg : Address and length of OTP controller and fuse map registers
|
||||
clocks : ipg clock we associate with the OCOTP peripheral
|
||||
|
||||
Example for Vybrid VF5xx/VF6xx:
|
||||
|
||||
ocotp: ocotp@400a5000 {
|
||||
compatible = "fsl,vf610-ocotp", "syscon";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x400a5000 0xCF0>;
|
||||
clocks = <&clks VF610_CLK_OCOTP>;
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
* ST SPEAr ADC device driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "st,spear600-adc"
|
||||
- reg: Address and length of the register set for the device
|
||||
- interrupts: Should contain the ADC interrupt
|
||||
- sampling-frequency: Default sampling frequency
|
||||
|
||||
Optional properties:
|
||||
- vref-external: External voltage reference in milli-volts. If omitted
|
||||
the internal voltage reference will be used.
|
||||
- average-samples: Number of samples to generate an average value. If
|
||||
omitted, single data conversion will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
adc: adc@d8200000 {
|
||||
compatible = "st,spear600-adc";
|
||||
reg = <0xd8200000 0x1000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <6>;
|
||||
sampling-frequency = <5000000>;
|
||||
vref-external = <2500>; /* 2.5V VRef */
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/trigger-source/gpio-trigger.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Generic trigger source using GPIO
|
||||
|
||||
description: A GPIO used as a trigger source.
|
||||
|
||||
maintainers:
|
||||
- Jonathan Santos <Jonathan.Santos@analog.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gpio-trigger
|
||||
|
||||
'#trigger-source-cells':
|
||||
const: 0
|
||||
|
||||
gpios:
|
||||
maxItems: 1
|
||||
description: GPIO to be used as a trigger source.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#trigger-source-cells'
|
||||
- gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
trigger {
|
||||
compatible = "gpio-trigger";
|
||||
#trigger-source-cells = <0>;
|
||||
gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
};
|
|
@ -1069,6 +1069,8 @@ patternProperties:
|
|||
description: Next Thing Co.
|
||||
"^ni,.*":
|
||||
description: National Instruments
|
||||
"^nicera,.*":
|
||||
description: Nippon Ceramic Co., Ltd.
|
||||
"^nintendo,.*":
|
||||
description: Nintendo
|
||||
"^nlt,.*":
|
||||
|
|
293
Documentation/iio/adxl313.rst
Normal file
293
Documentation/iio/adxl313.rst
Normal file
|
@ -0,0 +1,293 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===============
|
||||
ADXL313 driver
|
||||
===============
|
||||
|
||||
This driver supports Analog Device's ADXL313 on SPI/I2C bus.
|
||||
|
||||
1. Supported devices
|
||||
====================
|
||||
|
||||
* `ADXL313 <https://www.analog.com/ADXL313>`_
|
||||
|
||||
The ADXL313is a low noise density, low power, 3-axis accelerometer with
|
||||
selectable measurement ranges. The ADXL313 supports the ±0.5 g, ±1 g, ±2 g and
|
||||
±4 g ranges.
|
||||
|
||||
2. Device attributes
|
||||
====================
|
||||
|
||||
Accelerometer measurements are always provided.
|
||||
|
||||
Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
|
||||
where X is the IIO index of the device. Under these folders reside a set of
|
||||
device files, depending on the characteristics and features of the hardware
|
||||
device in questions. These files are consistently generalized and documented in
|
||||
the IIO ABI documentation.
|
||||
|
||||
The following tables show the adxl313 related device files, found in the
|
||||
specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
|
||||
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| 3-Axis Accelerometer related device files | Description |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_scale | Scale for the accelerometer channels. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_raw | Raw X-axis accelerometer channel value. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_calibbias | y-axis acceleration offset correction |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_z_raw | Raw Z-axis accelerometer channel value. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
|
||||
+---------------------------------------+----------------------------------------------+
|
||||
| Miscellaneous device files | Description |
|
||||
+---------------------------------------+----------------------------------------------+
|
||||
| name | Name of the IIO device. |
|
||||
+---------------------------------------+----------------------------------------------+
|
||||
| in_accel_sampling_frequency | Currently selected sample rate. |
|
||||
+---------------------------------------+----------------------------------------------+
|
||||
| in_accel_sampling_frequency_available | Available sampling frequency configurations. |
|
||||
+---------------------------------------+----------------------------------------------+
|
||||
|
||||
The iio event related settings, found in ``/sys/bus/iio/devices/iio:deviceX/events``.
|
||||
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_mag_adaptive_falling_period | AC coupled inactivity time. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_mag_adaptive_falling_value | AC coupled inactivity threshold. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_mag_adaptive_rising_value | AC coupled activity threshold. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_mag_falling_period | Inactivity time. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_mag_falling_value | Inactivity threshold. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_mag_rising_value | Activity threshold. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x\&y\&z_mag_adaptive_falling_en | Enable or disable AC coupled inactivity events. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x\|y\|z_mag_adaptive_rising_en | Enable or disable AC coupled activity events. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x\&y\&z_mag_falling_en | Enable or disable inactivity events. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x\|y\|z_mag_rising_en | Enable or disable activity events. |
|
||||
+---------------------------------------------------+----------------------------------------------------------+
|
||||
|
||||
The default coupling is DC coupled events. In this case the threshold will
|
||||
be in place as such, where for the AC coupled case an adaptive threshold
|
||||
(described in the datasheet) will be applied by the sensor. In general activity,
|
||||
i.e. ``ACTIVITY`` or ``ACTIVITY_AC`` and inactivity i.e. ``INACTIVITY`` or
|
||||
``INACTIVITY_AC``, will be linked with auto-sleep enabled when both are enabled.
|
||||
This means in particular ``ACTIVITY`` can also be linked to ``INACTIVITY_AC``
|
||||
and vice versa, without problem.
|
||||
|
||||
Note here, that ``ACTIVITY`` and ``ACTIVITY_AC`` are mutually exclusive. This
|
||||
means, that the most recent configuration will be set. For instance, if
|
||||
``ACTIVITY`` is enabled, and ``ACTIVITY_AC`` will be enabled, the sensor driver
|
||||
will have ``ACTIVITY`` disabled, but ``ACTIVITY_AC`` enabled. The same is valid
|
||||
for inactivity. In case of turning off an event, it has to match to what is
|
||||
actually enabled, i.e. enabling ``ACTIVITY_AC`` and then disabling ``ACTIVITY``
|
||||
is simply ignored as it is already disabled. Or, as if it was any other not
|
||||
enabled event, too.
|
||||
|
||||
Channels processed values
|
||||
-------------------------
|
||||
|
||||
A channel value can be read from its _raw attribute. The value returned is the
|
||||
raw value as reported by the devices. To get the processed value of the channel,
|
||||
apply the following formula:
|
||||
|
||||
.. code-block::
|
||||
|
||||
processed value = (_raw + _offset) * _scale
|
||||
|
||||
Where _offset and _scale are device attributes. If no _offset attribute is
|
||||
present, simply assume its value is 0.
|
||||
|
||||
The ADXL313 driver offers data for a single types of channels, the table below
|
||||
shows the measurement units for the processed value, which are defined by the
|
||||
IIO framework:
|
||||
|
||||
+-------------------------------------+---------------------------+
|
||||
| Channel type | Measurement unit |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Acceleration on X, Y, and Z axis | Meters per Second squared |
|
||||
+-------------------------------------+---------------------------+
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
Show device name:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat name
|
||||
adxl313
|
||||
|
||||
Show accelerometer channels value:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw
|
||||
2
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw
|
||||
-57
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw
|
||||
2
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale
|
||||
0.009576806
|
||||
|
||||
The accelerometer values will be:
|
||||
|
||||
- X-axis acceleration = in_accel_x_raw * in_accel_scale = 0.0191536 m/s^2
|
||||
- Y-axis acceleration = in_accel_y_raw * in_accel_scale = -0.5458779 m/s^2
|
||||
- Z-axis acceleration = in_accel_z_raw * in_accel_scale = 0.0191536 m/s^2
|
||||
|
||||
Set calibration offset for accelerometer channels. Note, that the calibration
|
||||
will be rounded according to the graduation of LSB units:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
|
||||
0
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 50 > in_accel_x_calibbias
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
|
||||
48
|
||||
|
||||
Set sampling frequency:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_sampling_frequency
|
||||
100.000000
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_sampling_frequency_available
|
||||
6.250000 12.500000 25.000000 50.000000 100.000000 200.000000 400.000000 800.000000 1600.000000 3200.000000
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 400 > in_accel_sampling_frequency
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_sampling_frequency
|
||||
400.000000
|
||||
|
||||
3. Device buffers and triggers
|
||||
==============================
|
||||
|
||||
This driver supports IIO buffers.
|
||||
|
||||
All devices support retrieving the raw acceleration measurements using buffers.
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
Select channels for buffer read:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_x_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_y_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_accel_z_en
|
||||
|
||||
Set the number of samples to be stored in the buffer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length
|
||||
|
||||
Enable buffer readings:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable
|
||||
|
||||
Obtain buffered data:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0
|
||||
...
|
||||
000000d0 01 fc 31 00 c7 ff 03 fc 31 00 c7 ff 04 fc 33 00 |..1.....1.....3.|
|
||||
000000e0 c8 ff 03 fc 32 00 c5 ff ff fc 32 00 c7 ff 0a fc |....2.....2.....|
|
||||
000000f0 30 00 c8 ff 06 fc 33 00 c7 ff 01 fc 2f 00 c8 ff |0.....3...../...|
|
||||
00000100 02 fc 32 00 c6 ff 04 fc 33 00 c8 ff 05 fc 33 00 |..2.....3.....3.|
|
||||
00000110 ca ff 02 fc 31 00 c7 ff 02 fc 30 00 c9 ff 09 fc |....1.....0.....|
|
||||
00000120 35 00 c9 ff 08 fc 35 00 c8 ff 02 fc 31 00 c5 ff |5.....5.....1...|
|
||||
00000130 03 fc 32 00 c7 ff 04 fc 32 00 c7 ff 02 fc 31 00 |..2.....2.....1.|
|
||||
00000140 c7 ff 08 fc 30 00 c7 ff 02 fc 32 00 c5 ff ff fc |....0.....2.....|
|
||||
00000150 31 00 c5 ff 04 fc 31 00 c8 ff 03 fc 32 00 c8 ff |1.....1.....2...|
|
||||
00000160 01 fc 31 00 c7 ff 05 fc 31 00 c3 ff 04 fc 31 00 |..1.....1.....1.|
|
||||
00000170 c5 ff 04 fc 30 00 c7 ff 03 fc 31 00 c9 ff 03 fc |....0.....1.....|
|
||||
...
|
||||
|
||||
Enabling activity detection:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1.28125 > ./events/in_accel_mag_rising_value
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_x\|y\|z_mag_rising_en
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> iio_event_monitor adxl313
|
||||
Found IIO device with name adxl313 with device number 0
|
||||
<only while moving the sensor>
|
||||
Event: time: 1748795762298351281, type: accel(x|y|z), channel: 0, evtype: mag, direction: rising
|
||||
Event: time: 1748795762302653704, type: accel(x|y|z), channel: 0, evtype: mag, direction: rising
|
||||
Event: time: 1748795762304340726, type: accel(x|y|z), channel: 0, evtype: mag, direction: rising
|
||||
...
|
||||
|
||||
Disabling activity detection:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 0 > ./events/in_accel_x\|y\|z_mag_rising_en
|
||||
root:/sys/bus/iio/devices/iio:device0> iio_event_monitor adxl313
|
||||
<nothing>
|
||||
|
||||
Enabling inactivity detection:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1.234375 > ./events/in_accel_mag_falling_value
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 5 > ./events/in_accel_mag_falling_period
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_x\&y\&z_mag_falling_en
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> iio_event_monitor adxl313
|
||||
Found IIO device with name adxl313 with device number 0
|
||||
Event: time: 1748796324115962975, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling
|
||||
Event: time: 1748796329329981772, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling
|
||||
Event: time: 1748796334543399706, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling
|
||||
...
|
||||
<every 5s now indicates inactivity>
|
||||
|
||||
Now, enabling activity, e.g. the AC coupled counter-part ``ACTIVITY_AC``
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1.28125 > ./events/in_accel_mag_rising_value
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > ./events/in_accel_x\|y\|z_mag_rising_en
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> iio_event_monitor adxl313
|
||||
Found IIO device with name adxl313 with device number 0
|
||||
<some activity with the sensor>
|
||||
Event: time: 1748796880354686777, type: accel(x|y|z), channel: 0, evtype: mag_adaptive, direction: rising
|
||||
<5s of inactivity, then>
|
||||
Event: time: 1748796885543252017, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling
|
||||
<some other activity detected by accelerating the sensor>
|
||||
Event: time: 1748796887756634678, type: accel(x|y|z), channel: 0, evtype: mag_adaptive, direction: rising
|
||||
<again, 5s of inactivity>
|
||||
Event: time: 1748796892964368352, type: accel(x&y&z), channel: 0, evtype: mag, direction: falling
|
||||
<stays like this until next activity in auto-sleep>
|
||||
|
||||
Note, when AC coupling is in place, the event type will be of ``mag_adaptive``.
|
||||
AC- or DC-coupled (the default) events are used similarly.
|
||||
|
||||
4. IIO Interfacing Tools
|
||||
========================
|
||||
|
||||
See Documentation/iio/iio_tools.rst for the description of the available IIO
|
||||
interfacing tools.
|
|
@ -31,6 +31,7 @@ Industrial I/O Kernel Drivers
|
|||
adis16475
|
||||
adis16480
|
||||
adis16550
|
||||
adxl313
|
||||
adxl380
|
||||
bno055
|
||||
ep93xx_adc
|
||||
|
|
24
MAINTAINERS
24
MAINTAINERS
|
@ -1385,6 +1385,14 @@ F: Documentation/devicetree/bindings/iio/adc/adi,ad4030.yaml
|
|||
F: Documentation/iio/ad4030.rst
|
||||
F: drivers/iio/adc/ad4030.c
|
||||
|
||||
ANALOG DEVICES INC AD4080 DRIVER
|
||||
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad4080.yaml
|
||||
F: drivers/iio/adc/ad4080.c
|
||||
|
||||
ANALOG DEVICES INC AD4130 DRIVER
|
||||
M: Cosmin Tanislav <cosmin.tanislav@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
|
@ -1394,6 +1402,14 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
|
|||
F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
|
||||
F: drivers/iio/adc/ad4130.c
|
||||
|
||||
ANALOG DEVICES INC AD4170-4 DRIVER
|
||||
M: Marcelo Schmitt <marcelo.schmitt@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad4170-4.yaml
|
||||
F: drivers/iio/adc/ad4170-4.c
|
||||
|
||||
ANALOG DEVICES INC AD4695 DRIVER
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
|
@ -1492,6 +1508,7 @@ S: Supported
|
|||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.yaml
|
||||
F: drivers/iio/adc/ad7768-1.c
|
||||
F: include/dt-bindings/iio/adc/adi,ad7768-1.h
|
||||
|
||||
ANALOG DEVICES INC AD7780 DRIVER
|
||||
M: Michael Hennerich <Michael.Hennerich@analog.com>
|
||||
|
@ -9443,7 +9460,7 @@ K: \bunsafe_memcpy\b
|
|||
K: \b__NO_FORTIFY\b
|
||||
|
||||
FPGA DFL DRIVERS
|
||||
M: Wu Hao <hao.wu@intel.com>
|
||||
M: Xu Yilun <yilun.xu@intel.com>
|
||||
R: Tom Rix <trix@redhat.com>
|
||||
L: linux-fpga@vger.kernel.org
|
||||
S: Maintained
|
||||
|
@ -9456,7 +9473,6 @@ F: include/uapi/linux/fpga-dfl.h
|
|||
|
||||
FPGA MANAGER FRAMEWORK
|
||||
M: Moritz Fischer <mdf@kernel.org>
|
||||
M: Wu Hao <hao.wu@intel.com>
|
||||
M: Xu Yilun <yilun.xu@intel.com>
|
||||
R: Tom Rix <trix@redhat.com>
|
||||
L: linux-fpga@vger.kernel.org
|
||||
|
@ -23611,7 +23627,6 @@ STAGING - INDUSTRIAL IO
|
|||
M: Jonathan Cameron <jic23@kernel.org>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
F: Documentation/devicetree/bindings/staging/iio/
|
||||
F: drivers/staging/iio/
|
||||
|
||||
STAGING - NVIDIA COMPLIANT EMBEDDED CONTROLLER INTERFACE (nvec)
|
||||
|
@ -25278,9 +25293,10 @@ M: David Lechner <dlechner@baylibre.com>
|
|||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/trigger-source/adi,util-sigma-delta-spi.yaml
|
||||
|
||||
TRIGGER SOURCE - PWM
|
||||
TRIGGER SOURCE
|
||||
M: David Lechner <dlechner@baylibre.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/trigger-source/gpio-trigger.yaml
|
||||
F: Documentation/devicetree/bindings/trigger-source/pwm-trigger.yaml
|
||||
|
||||
TRUSTED SECURITY MODULE (TSM) INFRASTRUCTURE
|
||||
|
|
|
@ -10,6 +10,12 @@ source "drivers/cxl/Kconfig"
|
|||
source "drivers/pcmcia/Kconfig"
|
||||
source "drivers/rapidio/Kconfig"
|
||||
|
||||
config PC104
|
||||
bool "PC/104 support" if EXPERT
|
||||
help
|
||||
Expose PC/104 form factor device drivers and options available for
|
||||
selection and configuration. Enable this option if your target
|
||||
machine has a PC/104 bus.
|
||||
|
||||
source "drivers/base/Kconfig"
|
||||
|
||||
|
|
|
@ -37,14 +37,15 @@ config ANDROID_BINDER_DEVICES
|
|||
created. Each binder device has its own context manager, and is
|
||||
therefore logically separated from the other devices.
|
||||
|
||||
config ANDROID_BINDER_IPC_SELFTEST
|
||||
bool "Android Binder IPC Driver Selftest"
|
||||
depends on ANDROID_BINDER_IPC
|
||||
config ANDROID_BINDER_ALLOC_KUNIT_TEST
|
||||
tristate "KUnit Tests for Android Binder Alloc" if !KUNIT_ALL_TESTS
|
||||
depends on ANDROID_BINDER_IPC && KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
This feature allows binder selftest to run.
|
||||
This feature builds the binder alloc KUnit tests.
|
||||
|
||||
Binder selftest checks the allocation and free of binder buffers
|
||||
exhaustively with combinations of various buffer sizes and
|
||||
alignments.
|
||||
Each test case runs using a pared-down binder_alloc struct and
|
||||
test-specific freelist, which allows this KUnit module to be loaded
|
||||
for testing without interfering with a running system.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -3,4 +3,4 @@ ccflags-y += -I$(src) # needed for trace events
|
|||
|
||||
obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/
|
||||
|
|
|
@ -68,6 +68,8 @@
|
|||
#include <linux/sizes.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include <kunit/visibility.h>
|
||||
|
||||
#include <uapi/linux/android/binder.h>
|
||||
|
||||
#include <linux/cacheflush.h>
|
||||
|
@ -1585,11 +1587,10 @@ static struct binder_thread *binder_get_txn_from(
|
|||
{
|
||||
struct binder_thread *from;
|
||||
|
||||
spin_lock(&t->lock);
|
||||
guard(spinlock)(&t->lock);
|
||||
from = t->from;
|
||||
if (from)
|
||||
atomic_inc(&from->tmp_ref);
|
||||
spin_unlock(&t->lock);
|
||||
return from;
|
||||
}
|
||||
|
||||
|
@ -3144,10 +3145,8 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
}
|
||||
if (!target_node) {
|
||||
binder_txn_error("%d:%d cannot find target node\n",
|
||||
thread->pid, proc->pid);
|
||||
/*
|
||||
* return_error is set above
|
||||
*/
|
||||
proc->pid, thread->pid);
|
||||
/* return_error is set above */
|
||||
return_error_param = -EINVAL;
|
||||
return_error_line = __LINE__;
|
||||
goto err_dead_binder;
|
||||
|
@ -5437,32 +5436,28 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp,
|
|||
struct binder_node *new_node;
|
||||
kuid_t curr_euid = current_euid();
|
||||
|
||||
mutex_lock(&context->context_mgr_node_lock);
|
||||
guard(mutex)(&context->context_mgr_node_lock);
|
||||
if (context->binder_context_mgr_node) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
return -EBUSY;
|
||||
}
|
||||
ret = security_binder_set_context_mgr(proc->cred);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
if (uid_valid(context->binder_context_mgr_uid)) {
|
||||
if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
|
||||
from_kuid(&init_user_ns, curr_euid),
|
||||
from_kuid(&init_user_ns,
|
||||
context->binder_context_mgr_uid));
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
return -EPERM;
|
||||
}
|
||||
} else {
|
||||
context->binder_context_mgr_uid = curr_euid;
|
||||
}
|
||||
new_node = binder_new_node(proc, fbo);
|
||||
if (!new_node) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!new_node)
|
||||
return -ENOMEM;
|
||||
binder_node_lock(new_node);
|
||||
new_node->local_weak_refs++;
|
||||
new_node->local_strong_refs++;
|
||||
|
@ -5471,8 +5466,6 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp,
|
|||
context->binder_context_mgr_node = new_node;
|
||||
binder_node_unlock(new_node);
|
||||
binder_put_node(new_node);
|
||||
out:
|
||||
mutex_unlock(&context->context_mgr_node_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5708,11 +5701,6 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
struct binder_thread *thread;
|
||||
void __user *ubuf = (void __user *)arg;
|
||||
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
|
||||
proc->pid, current->pid, cmd, arg);*/
|
||||
|
||||
binder_selftest_alloc(&proc->alloc);
|
||||
|
||||
trace_binder_ioctl(cmd, arg);
|
||||
|
||||
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
|
||||
|
@ -5948,10 +5936,11 @@ static void binder_vma_close(struct vm_area_struct *vma)
|
|||
binder_alloc_vma_close(&proc->alloc);
|
||||
}
|
||||
|
||||
static vm_fault_t binder_vm_fault(struct vm_fault *vmf)
|
||||
VISIBLE_IF_KUNIT vm_fault_t binder_vm_fault(struct vm_fault *vmf)
|
||||
{
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_vm_fault);
|
||||
|
||||
static const struct vm_operations_struct binder_vm_ops = {
|
||||
.open = binder_vma_open,
|
||||
|
@ -6314,14 +6303,13 @@ static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
|
|||
static void
|
||||
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
|
||||
{
|
||||
mutex_lock(&binder_deferred_lock);
|
||||
guard(mutex)(&binder_deferred_lock);
|
||||
proc->deferred_work |= defer;
|
||||
if (hlist_unhashed(&proc->deferred_work_node)) {
|
||||
hlist_add_head(&proc->deferred_work_node,
|
||||
&binder_deferred_list);
|
||||
schedule_work(&binder_deferred_work);
|
||||
}
|
||||
mutex_unlock(&binder_deferred_lock);
|
||||
}
|
||||
|
||||
static void print_binder_transaction_ilocked(struct seq_file *m,
|
||||
|
@ -6863,14 +6851,13 @@ static int proc_show(struct seq_file *m, void *unused)
|
|||
struct binder_proc *itr;
|
||||
int pid = (unsigned long)m->private;
|
||||
|
||||
mutex_lock(&binder_procs_lock);
|
||||
guard(mutex)(&binder_procs_lock);
|
||||
hlist_for_each_entry(itr, &binder_procs, proc_node) {
|
||||
if (itr->pid == pid) {
|
||||
seq_puts(m, "binder proc state:\n");
|
||||
print_binder_proc(m, itr, true, false);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&binder_procs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6988,16 +6975,14 @@ const struct binder_debugfs_entry binder_debugfs_entries[] = {
|
|||
|
||||
void binder_add_device(struct binder_device *device)
|
||||
{
|
||||
spin_lock(&binder_devices_lock);
|
||||
guard(spinlock)(&binder_devices_lock);
|
||||
hlist_add_head(&device->hlist, &binder_devices);
|
||||
spin_unlock(&binder_devices_lock);
|
||||
}
|
||||
|
||||
void binder_remove_device(struct binder_device *device)
|
||||
{
|
||||
spin_lock(&binder_devices_lock);
|
||||
guard(spinlock)(&binder_devices_lock);
|
||||
hlist_del_init(&device->hlist);
|
||||
spin_unlock(&binder_devices_lock);
|
||||
}
|
||||
|
||||
static int __init init_binder_device(const char *name)
|
||||
|
|
|
@ -23,10 +23,11 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <kunit/visibility.h>
|
||||
#include "binder_alloc.h"
|
||||
#include "binder_trace.h"
|
||||
|
||||
struct list_lru binder_freelist;
|
||||
static struct list_lru binder_freelist;
|
||||
|
||||
static DEFINE_MUTEX(binder_alloc_mmap_lock);
|
||||
|
||||
|
@ -57,13 +58,14 @@ static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer)
|
|||
return list_entry(buffer->entry.prev, struct binder_buffer, entry);
|
||||
}
|
||||
|
||||
static size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer)
|
||||
VISIBLE_IF_KUNIT size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer)
|
||||
{
|
||||
if (list_is_last(&buffer->entry, &alloc->buffers))
|
||||
return alloc->vm_start + alloc->buffer_size - buffer->user_data;
|
||||
return binder_buffer_next(buffer)->user_data - buffer->user_data;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_buffer_size);
|
||||
|
||||
static void binder_insert_free_buffer(struct binder_alloc *alloc,
|
||||
struct binder_buffer *new_buffer)
|
||||
|
@ -167,12 +169,8 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked(
|
|||
struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc,
|
||||
unsigned long user_ptr)
|
||||
{
|
||||
struct binder_buffer *buffer;
|
||||
|
||||
mutex_lock(&alloc->mutex);
|
||||
buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr);
|
||||
mutex_unlock(&alloc->mutex);
|
||||
return buffer;
|
||||
guard(mutex)(&alloc->mutex);
|
||||
return binder_alloc_prepare_to_free_locked(alloc, user_ptr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -210,7 +208,7 @@ static void binder_lru_freelist_add(struct binder_alloc *alloc,
|
|||
|
||||
trace_binder_free_lru_start(alloc, index);
|
||||
|
||||
ret = list_lru_add(&binder_freelist,
|
||||
ret = list_lru_add(alloc->freelist,
|
||||
page_to_lru(page),
|
||||
page_to_nid(page),
|
||||
NULL);
|
||||
|
@ -409,7 +407,7 @@ static void binder_lru_freelist_del(struct binder_alloc *alloc,
|
|||
if (page) {
|
||||
trace_binder_alloc_lru_start(alloc, index);
|
||||
|
||||
on_lru = list_lru_del(&binder_freelist,
|
||||
on_lru = list_lru_del(alloc->freelist,
|
||||
page_to_lru(page),
|
||||
page_to_nid(page),
|
||||
NULL);
|
||||
|
@ -699,6 +697,7 @@ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
|
|||
out:
|
||||
return buffer;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_new_buf);
|
||||
|
||||
static unsigned long buffer_start_page(struct binder_buffer *buffer)
|
||||
{
|
||||
|
@ -877,6 +876,7 @@ void binder_alloc_free_buf(struct binder_alloc *alloc,
|
|||
binder_free_buf_locked(alloc, buffer);
|
||||
mutex_unlock(&alloc->mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_free_buf);
|
||||
|
||||
/**
|
||||
* binder_alloc_mmap_handler() - map virtual address space for proc
|
||||
|
@ -959,7 +959,7 @@ err_invalid_mm:
|
|||
failure_string, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_mmap_handler);
|
||||
|
||||
void binder_alloc_deferred_release(struct binder_alloc *alloc)
|
||||
{
|
||||
|
@ -1007,7 +1007,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
|
|||
if (!page)
|
||||
continue;
|
||||
|
||||
on_lru = list_lru_del(&binder_freelist,
|
||||
on_lru = list_lru_del(alloc->freelist,
|
||||
page_to_lru(page),
|
||||
page_to_nid(page),
|
||||
NULL);
|
||||
|
@ -1028,6 +1028,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
|
|||
"%s: %d buffers %d, pages %d\n",
|
||||
__func__, alloc->pid, buffers, page_count);
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_deferred_release);
|
||||
|
||||
/**
|
||||
* binder_alloc_print_allocated() - print buffer info
|
||||
|
@ -1043,7 +1044,7 @@ void binder_alloc_print_allocated(struct seq_file *m,
|
|||
struct binder_buffer *buffer;
|
||||
struct rb_node *n;
|
||||
|
||||
mutex_lock(&alloc->mutex);
|
||||
guard(mutex)(&alloc->mutex);
|
||||
for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) {
|
||||
buffer = rb_entry(n, struct binder_buffer, rb_node);
|
||||
seq_printf(m, " buffer %d: %lx size %zd:%zd:%zd %s\n",
|
||||
|
@ -1053,7 +1054,6 @@ void binder_alloc_print_allocated(struct seq_file *m,
|
|||
buffer->extra_buffers_size,
|
||||
buffer->transaction ? "active" : "delivered");
|
||||
}
|
||||
mutex_unlock(&alloc->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1102,10 +1102,9 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc)
|
|||
struct rb_node *n;
|
||||
int count = 0;
|
||||
|
||||
mutex_lock(&alloc->mutex);
|
||||
guard(mutex)(&alloc->mutex);
|
||||
for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n))
|
||||
count++;
|
||||
mutex_unlock(&alloc->mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1122,6 +1121,7 @@ void binder_alloc_vma_close(struct binder_alloc *alloc)
|
|||
{
|
||||
binder_alloc_set_mapped(alloc, false);
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_vma_close);
|
||||
|
||||
/**
|
||||
* binder_alloc_free_page() - shrinker callback to free pages
|
||||
|
@ -1213,6 +1213,7 @@ err_mmap_read_lock_failed:
|
|||
err_mmget:
|
||||
return LRU_SKIP;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(binder_alloc_free_page);
|
||||
|
||||
static unsigned long
|
||||
binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
|
||||
|
@ -1229,6 +1230,18 @@ binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
|||
|
||||
static struct shrinker *binder_shrinker;
|
||||
|
||||
VISIBLE_IF_KUNIT void __binder_alloc_init(struct binder_alloc *alloc,
|
||||
struct list_lru *freelist)
|
||||
{
|
||||
alloc->pid = current->group_leader->pid;
|
||||
alloc->mm = current->mm;
|
||||
mmgrab(alloc->mm);
|
||||
mutex_init(&alloc->mutex);
|
||||
INIT_LIST_HEAD(&alloc->buffers);
|
||||
alloc->freelist = freelist;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(__binder_alloc_init);
|
||||
|
||||
/**
|
||||
* binder_alloc_init() - called by binder_open() for per-proc initialization
|
||||
* @alloc: binder_alloc for this proc
|
||||
|
@ -1238,11 +1251,7 @@ static struct shrinker *binder_shrinker;
|
|||
*/
|
||||
void binder_alloc_init(struct binder_alloc *alloc)
|
||||
{
|
||||
alloc->pid = current->group_leader->pid;
|
||||
alloc->mm = current->mm;
|
||||
mmgrab(alloc->mm);
|
||||
mutex_init(&alloc->mutex);
|
||||
INIT_LIST_HEAD(&alloc->buffers);
|
||||
__binder_alloc_init(alloc, &binder_freelist);
|
||||
}
|
||||
|
||||
int binder_alloc_shrinker_init(void)
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/list_lru.h>
|
||||
#include <uapi/linux/android/binder.h>
|
||||
|
||||
extern struct list_lru binder_freelist;
|
||||
struct binder_transaction;
|
||||
|
||||
/**
|
||||
|
@ -91,6 +90,7 @@ static inline struct list_head *page_to_lru(struct page *p)
|
|||
* @free_async_space: VA space available for async buffers. This is
|
||||
* initialized at mmap time to 1/2 the full VA space
|
||||
* @pages: array of struct page *
|
||||
* @freelist: lru list to use for free pages (invariant after init)
|
||||
* @buffer_size: size of address space specified via mmap
|
||||
* @pid: pid for associated binder_proc (invariant after init)
|
||||
* @pages_high: high watermark of offset in @pages
|
||||
|
@ -113,6 +113,7 @@ struct binder_alloc {
|
|||
struct rb_root allocated_buffers;
|
||||
size_t free_async_space;
|
||||
struct page **pages;
|
||||
struct list_lru *freelist;
|
||||
size_t buffer_size;
|
||||
int pid;
|
||||
size_t pages_high;
|
||||
|
@ -120,11 +121,6 @@ struct binder_alloc {
|
|||
bool oneway_spam_detected;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST
|
||||
void binder_selftest_alloc(struct binder_alloc *alloc);
|
||||
#else
|
||||
static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
|
||||
#endif
|
||||
enum lru_status binder_alloc_free_page(struct list_head *item,
|
||||
struct list_lru_one *lru,
|
||||
void *cb_arg);
|
||||
|
@ -160,12 +156,8 @@ void binder_alloc_print_pages(struct seq_file *m,
|
|||
static inline size_t
|
||||
binder_alloc_get_free_async_space(struct binder_alloc *alloc)
|
||||
{
|
||||
size_t free_async_space;
|
||||
|
||||
mutex_lock(&alloc->mutex);
|
||||
free_async_space = alloc->free_async_space;
|
||||
mutex_unlock(&alloc->mutex);
|
||||
return free_async_space;
|
||||
guard(mutex)(&alloc->mutex);
|
||||
return alloc->free_async_space;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
|
@ -187,5 +179,11 @@ int binder_alloc_copy_from_buffer(struct binder_alloc *alloc,
|
|||
binder_size_t buffer_offset,
|
||||
size_t bytes);
|
||||
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
void __binder_alloc_init(struct binder_alloc *alloc, struct list_lru *freelist);
|
||||
size_t binder_alloc_buffer_size(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer);
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_BINDER_ALLOC_H */
|
||||
|
||||
|
|
|
@ -1,306 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* binder_alloc_selftest.c
|
||||
*
|
||||
* Android IPC Subsystem
|
||||
*
|
||||
* Copyright (C) 2017 Google, Inc.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/err.h>
|
||||
#include "binder_alloc.h"
|
||||
|
||||
#define BUFFER_NUM 5
|
||||
#define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
|
||||
|
||||
static bool binder_selftest_run = true;
|
||||
static int binder_selftest_failures;
|
||||
static DEFINE_MUTEX(binder_selftest_lock);
|
||||
|
||||
/**
|
||||
* enum buf_end_align_type - Page alignment of a buffer
|
||||
* end with regard to the end of the previous buffer.
|
||||
*
|
||||
* In the pictures below, buf2 refers to the buffer we
|
||||
* are aligning. buf1 refers to previous buffer by addr.
|
||||
* Symbol [ means the start of a buffer, ] means the end
|
||||
* of a buffer, and | means page boundaries.
|
||||
*/
|
||||
enum buf_end_align_type {
|
||||
/**
|
||||
* @SAME_PAGE_UNALIGNED: The end of this buffer is on
|
||||
* the same page as the end of the previous buffer and
|
||||
* is not page aligned. Examples:
|
||||
* buf1 ][ buf2 ][ ...
|
||||
* buf1 ]|[ buf2 ][ ...
|
||||
*/
|
||||
SAME_PAGE_UNALIGNED = 0,
|
||||
/**
|
||||
* @SAME_PAGE_ALIGNED: When the end of the previous buffer
|
||||
* is not page aligned, the end of this buffer is on the
|
||||
* same page as the end of the previous buffer and is page
|
||||
* aligned. When the previous buffer is page aligned, the
|
||||
* end of this buffer is aligned to the next page boundary.
|
||||
* Examples:
|
||||
* buf1 ][ buf2 ]| ...
|
||||
* buf1 ]|[ buf2 ]| ...
|
||||
*/
|
||||
SAME_PAGE_ALIGNED,
|
||||
/**
|
||||
* @NEXT_PAGE_UNALIGNED: The end of this buffer is on
|
||||
* the page next to the end of the previous buffer and
|
||||
* is not page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 ][ ...
|
||||
* buf1 ]|[ buf2 | buf2 ][ ...
|
||||
*/
|
||||
NEXT_PAGE_UNALIGNED,
|
||||
/**
|
||||
* @NEXT_PAGE_ALIGNED: The end of this buffer is on
|
||||
* the page next to the end of the previous buffer and
|
||||
* is page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 ]| ...
|
||||
* buf1 ]|[ buf2 | buf2 ]| ...
|
||||
*/
|
||||
NEXT_PAGE_ALIGNED,
|
||||
/**
|
||||
* @NEXT_NEXT_UNALIGNED: The end of this buffer is on
|
||||
* the page that follows the page after the end of the
|
||||
* previous buffer and is not page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 | buf2 ][ ...
|
||||
* buf1 ]|[ buf2 | buf2 | buf2 ][ ...
|
||||
*/
|
||||
NEXT_NEXT_UNALIGNED,
|
||||
/**
|
||||
* @LOOP_END: The number of enum values in &buf_end_align_type.
|
||||
* It is used for controlling loop termination.
|
||||
*/
|
||||
LOOP_END,
|
||||
};
|
||||
|
||||
static void pr_err_size_seq(size_t *sizes, int *seq)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_err("alloc sizes: ");
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
pr_cont("[%zu]", sizes[i]);
|
||||
pr_cont("\n");
|
||||
pr_err("free seq: ");
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
pr_cont("[%d]", seq[i]);
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
static bool check_buffer_pages_allocated(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer,
|
||||
size_t size)
|
||||
{
|
||||
unsigned long page_addr;
|
||||
unsigned long end;
|
||||
int page_index;
|
||||
|
||||
end = PAGE_ALIGN(buffer->user_data + size);
|
||||
page_addr = buffer->user_data;
|
||||
for (; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
page_index = (page_addr - alloc->vm_start) / PAGE_SIZE;
|
||||
if (!alloc->pages[page_index] ||
|
||||
!list_empty(page_to_lru(alloc->pages[page_index]))) {
|
||||
pr_err("expect alloc but is %s at page index %d\n",
|
||||
alloc->pages[page_index] ?
|
||||
"lru" : "free", page_index);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffers[],
|
||||
size_t *sizes, int *seq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
|
||||
if (IS_ERR(buffers[i]) ||
|
||||
!check_buffer_pages_allocated(alloc, buffers[i],
|
||||
sizes[i])) {
|
||||
pr_err_size_seq(sizes, seq);
|
||||
binder_selftest_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_free_buf(struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffers[],
|
||||
size_t *sizes, int *seq, size_t end)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
binder_alloc_free_buf(alloc, buffers[seq[i]]);
|
||||
|
||||
for (i = 0; i < end / PAGE_SIZE; i++) {
|
||||
/**
|
||||
* Error message on a free page can be false positive
|
||||
* if binder shrinker ran during binder_alloc_free_buf
|
||||
* calls above.
|
||||
*/
|
||||
if (list_empty(page_to_lru(alloc->pages[i]))) {
|
||||
pr_err_size_seq(sizes, seq);
|
||||
pr_err("expect lru but is %s at page index %d\n",
|
||||
alloc->pages[i] ? "alloc" : "free", i);
|
||||
binder_selftest_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_free_page(struct binder_alloc *alloc)
|
||||
{
|
||||
int i;
|
||||
unsigned long count;
|
||||
|
||||
while ((count = list_lru_count(&binder_freelist))) {
|
||||
list_lru_walk(&binder_freelist, binder_alloc_free_page,
|
||||
NULL, count);
|
||||
}
|
||||
|
||||
for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
|
||||
if (alloc->pages[i]) {
|
||||
pr_err("expect free but is %s at page index %d\n",
|
||||
list_empty(page_to_lru(alloc->pages[i])) ?
|
||||
"alloc" : "lru", i);
|
||||
binder_selftest_failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_free(struct binder_alloc *alloc,
|
||||
size_t *sizes, int *seq, size_t end)
|
||||
{
|
||||
struct binder_buffer *buffers[BUFFER_NUM];
|
||||
|
||||
binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
|
||||
binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
|
||||
|
||||
/* Allocate from lru. */
|
||||
binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
|
||||
if (list_lru_count(&binder_freelist))
|
||||
pr_err("lru list should be empty but is not\n");
|
||||
|
||||
binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
|
||||
binder_selftest_free_page(alloc);
|
||||
}
|
||||
|
||||
static bool is_dup(int *seq, int index, int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < index; i++) {
|
||||
if (seq[i] == val)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Generate BUFFER_NUM factorial free orders. */
|
||||
static void binder_selftest_free_seq(struct binder_alloc *alloc,
|
||||
size_t *sizes, int *seq,
|
||||
int index, size_t end)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (index == BUFFER_NUM) {
|
||||
binder_selftest_alloc_free(alloc, sizes, seq, end);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
if (is_dup(seq, index, i))
|
||||
continue;
|
||||
seq[index] = i;
|
||||
binder_selftest_free_seq(alloc, sizes, seq, index + 1, end);
|
||||
}
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_size(struct binder_alloc *alloc,
|
||||
size_t *end_offset)
|
||||
{
|
||||
int i;
|
||||
int seq[BUFFER_NUM] = {0};
|
||||
size_t front_sizes[BUFFER_NUM];
|
||||
size_t back_sizes[BUFFER_NUM];
|
||||
size_t last_offset, offset = 0;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
last_offset = offset;
|
||||
offset = end_offset[i];
|
||||
front_sizes[i] = offset - last_offset;
|
||||
back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
|
||||
}
|
||||
/*
|
||||
* Buffers share the first or last few pages.
|
||||
* Only BUFFER_NUM - 1 buffer sizes are adjustable since
|
||||
* we need one giant buffer before getting to the last page.
|
||||
*/
|
||||
back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
|
||||
binder_selftest_free_seq(alloc, front_sizes, seq, 0,
|
||||
end_offset[BUFFER_NUM - 1]);
|
||||
binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size);
|
||||
}
|
||||
|
||||
static void binder_selftest_alloc_offset(struct binder_alloc *alloc,
|
||||
size_t *end_offset, int index)
|
||||
{
|
||||
int align;
|
||||
size_t end, prev;
|
||||
|
||||
if (index == BUFFER_NUM) {
|
||||
binder_selftest_alloc_size(alloc, end_offset);
|
||||
return;
|
||||
}
|
||||
prev = index == 0 ? 0 : end_offset[index - 1];
|
||||
end = prev;
|
||||
|
||||
BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
|
||||
|
||||
for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
|
||||
if (align % 2)
|
||||
end = ALIGN(end, PAGE_SIZE);
|
||||
else
|
||||
end += BUFFER_MIN_SIZE;
|
||||
end_offset[index] = end;
|
||||
binder_selftest_alloc_offset(alloc, end_offset, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_selftest_alloc() - Test alloc and free of buffer pages.
|
||||
* @alloc: Pointer to alloc struct.
|
||||
*
|
||||
* Allocate BUFFER_NUM buffers to cover all page alignment cases,
|
||||
* then free them in all orders possible. Check that pages are
|
||||
* correctly allocated, put onto lru when buffers are freed, and
|
||||
* are freed when binder_alloc_free_page is called.
|
||||
*/
|
||||
void binder_selftest_alloc(struct binder_alloc *alloc)
|
||||
{
|
||||
size_t end_offset[BUFFER_NUM];
|
||||
|
||||
if (!binder_selftest_run)
|
||||
return;
|
||||
mutex_lock(&binder_selftest_lock);
|
||||
if (!binder_selftest_run || !alloc->mapped)
|
||||
goto done;
|
||||
pr_info("STARTED\n");
|
||||
binder_selftest_alloc_offset(alloc, end_offset, 0);
|
||||
binder_selftest_run = false;
|
||||
if (binder_selftest_failures > 0)
|
||||
pr_info("%d tests FAILED\n", binder_selftest_failures);
|
||||
else
|
||||
pr_info("PASSED\n");
|
||||
|
||||
done:
|
||||
mutex_unlock(&binder_selftest_lock);
|
||||
}
|
|
@ -590,4 +590,8 @@ void binder_add_device(struct binder_device *device);
|
|||
*/
|
||||
void binder_remove_device(struct binder_device *device);
|
||||
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
vm_fault_t binder_vm_fault(struct vm_fault *vmf);
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_BINDER_INTERNAL_H */
|
||||
|
|
|
@ -34,27 +34,6 @@ TRACE_EVENT(binder_ioctl,
|
|||
TP_printk("cmd=0x%x arg=0x%lx", __entry->cmd, __entry->arg)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(binder_lock_class,
|
||||
TP_PROTO(const char *tag),
|
||||
TP_ARGS(tag),
|
||||
TP_STRUCT__entry(
|
||||
__field(const char *, tag)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->tag = tag;
|
||||
),
|
||||
TP_printk("tag=%s", __entry->tag)
|
||||
);
|
||||
|
||||
#define DEFINE_BINDER_LOCK_EVENT(name) \
|
||||
DEFINE_EVENT(binder_lock_class, name, \
|
||||
TP_PROTO(const char *func), \
|
||||
TP_ARGS(func))
|
||||
|
||||
DEFINE_BINDER_LOCK_EVENT(binder_lock);
|
||||
DEFINE_BINDER_LOCK_EVENT(binder_locked);
|
||||
DEFINE_BINDER_LOCK_EVENT(binder_unlock);
|
||||
|
||||
DECLARE_EVENT_CLASS(binder_function_return_class,
|
||||
TP_PROTO(int ret),
|
||||
TP_ARGS(ret),
|
||||
|
|
|
@ -117,7 +117,6 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
|
|||
struct dentry *dentry, *root;
|
||||
struct binder_device *device;
|
||||
char *name = NULL;
|
||||
size_t name_len;
|
||||
struct inode *inode = NULL;
|
||||
struct super_block *sb = ref_inode->i_sb;
|
||||
struct binderfs_info *info = sb->s_fs_info;
|
||||
|
@ -161,9 +160,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
|
|||
inode->i_gid = info->root_gid;
|
||||
|
||||
req->name[BINDERFS_MAX_NAME] = '\0'; /* NUL-terminate */
|
||||
name_len = strlen(req->name);
|
||||
/* Make sure to include terminating NUL byte */
|
||||
name = kmemdup(req->name, name_len + 1, GFP_KERNEL);
|
||||
name = kstrdup(req->name, GFP_KERNEL);
|
||||
if (!name)
|
||||
goto err;
|
||||
|
||||
|
|
7
drivers/android/tests/.kunitconfig
Normal file
7
drivers/android/tests/.kunitconfig
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# Copyright 2025 Google LLC.
|
||||
#
|
||||
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST=y
|
6
drivers/android/tests/Makefile
Normal file
6
drivers/android/tests/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# Copyright 2025 Google LLC.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += binder_alloc_kunit.o
|
572
drivers/android/tests/binder_alloc_kunit.c
Normal file
572
drivers/android/tests/binder_alloc_kunit.c
Normal file
|
@ -0,0 +1,572 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Test cases for binder allocator code.
|
||||
*
|
||||
* Copyright 2025 Google LLC.
|
||||
* Author: Tiffany Yang <ynaffit@google.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/seq_buf.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include "../binder_alloc.h"
|
||||
#include "../binder_internal.h"
|
||||
|
||||
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
|
||||
|
||||
#define BINDER_MMAP_SIZE SZ_128K
|
||||
|
||||
#define BUFFER_NUM 5
|
||||
#define BUFFER_MIN_SIZE (PAGE_SIZE / 8)
|
||||
|
||||
#define FREESEQ_BUFLEN ((3 * BUFFER_NUM) + 1)
|
||||
|
||||
#define ALIGN_TYPE_STRLEN (12)
|
||||
|
||||
#define ALIGNMENTS_BUFLEN (((ALIGN_TYPE_STRLEN + 6) * BUFFER_NUM) + 1)
|
||||
|
||||
#define PRINT_ALL_CASES (0)
|
||||
|
||||
/* 5^5 alignment combinations * 2 places to share pages * 5! free sequences */
|
||||
#define TOTAL_EXHAUSTIVE_CASES (3125 * 2 * 120)
|
||||
|
||||
/**
|
||||
* enum buf_end_align_type - Page alignment of a buffer
|
||||
* end with regard to the end of the previous buffer.
|
||||
*
|
||||
* In the pictures below, buf2 refers to the buffer we
|
||||
* are aligning. buf1 refers to previous buffer by addr.
|
||||
* Symbol [ means the start of a buffer, ] means the end
|
||||
* of a buffer, and | means page boundaries.
|
||||
*/
|
||||
enum buf_end_align_type {
|
||||
/**
|
||||
* @SAME_PAGE_UNALIGNED: The end of this buffer is on
|
||||
* the same page as the end of the previous buffer and
|
||||
* is not page aligned. Examples:
|
||||
* buf1 ][ buf2 ][ ...
|
||||
* buf1 ]|[ buf2 ][ ...
|
||||
*/
|
||||
SAME_PAGE_UNALIGNED = 0,
|
||||
/**
|
||||
* @SAME_PAGE_ALIGNED: When the end of the previous buffer
|
||||
* is not page aligned, the end of this buffer is on the
|
||||
* same page as the end of the previous buffer and is page
|
||||
* aligned. When the previous buffer is page aligned, the
|
||||
* end of this buffer is aligned to the next page boundary.
|
||||
* Examples:
|
||||
* buf1 ][ buf2 ]| ...
|
||||
* buf1 ]|[ buf2 ]| ...
|
||||
*/
|
||||
SAME_PAGE_ALIGNED,
|
||||
/**
|
||||
* @NEXT_PAGE_UNALIGNED: The end of this buffer is on
|
||||
* the page next to the end of the previous buffer and
|
||||
* is not page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 ][ ...
|
||||
* buf1 ]|[ buf2 | buf2 ][ ...
|
||||
*/
|
||||
NEXT_PAGE_UNALIGNED,
|
||||
/**
|
||||
* @NEXT_PAGE_ALIGNED: The end of this buffer is on
|
||||
* the page next to the end of the previous buffer and
|
||||
* is page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 ]| ...
|
||||
* buf1 ]|[ buf2 | buf2 ]| ...
|
||||
*/
|
||||
NEXT_PAGE_ALIGNED,
|
||||
/**
|
||||
* @NEXT_NEXT_UNALIGNED: The end of this buffer is on
|
||||
* the page that follows the page after the end of the
|
||||
* previous buffer and is not page aligned. Examples:
|
||||
* buf1 ][ buf2 | buf2 | buf2 ][ ...
|
||||
* buf1 ]|[ buf2 | buf2 | buf2 ][ ...
|
||||
*/
|
||||
NEXT_NEXT_UNALIGNED,
|
||||
/**
|
||||
* @LOOP_END: The number of enum values in &buf_end_align_type.
|
||||
* It is used for controlling loop termination.
|
||||
*/
|
||||
LOOP_END,
|
||||
};
|
||||
|
||||
static const char *const buf_end_align_type_strs[LOOP_END] = {
|
||||
[SAME_PAGE_UNALIGNED] = "SP_UNALIGNED",
|
||||
[SAME_PAGE_ALIGNED] = " SP_ALIGNED ",
|
||||
[NEXT_PAGE_UNALIGNED] = "NP_UNALIGNED",
|
||||
[NEXT_PAGE_ALIGNED] = " NP_ALIGNED ",
|
||||
[NEXT_NEXT_UNALIGNED] = "NN_UNALIGNED",
|
||||
};
|
||||
|
||||
struct binder_alloc_test_case_info {
|
||||
char alignments[ALIGNMENTS_BUFLEN];
|
||||
struct seq_buf alignments_sb;
|
||||
size_t *buffer_sizes;
|
||||
int *free_sequence;
|
||||
bool front_pages;
|
||||
};
|
||||
|
||||
static void stringify_free_seq(struct kunit *test, int *seq, struct seq_buf *sb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
seq_buf_printf(sb, "[%d]", seq[i]);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(sb));
|
||||
}
|
||||
|
||||
static void stringify_alignments(struct kunit *test, int *alignments,
|
||||
struct seq_buf *sb)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
seq_buf_printf(sb, "[ %d:%s ]", i,
|
||||
buf_end_align_type_strs[alignments[i]]);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(sb));
|
||||
}
|
||||
|
||||
static bool check_buffer_pages_allocated(struct kunit *test,
|
||||
struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffer,
|
||||
size_t size)
|
||||
{
|
||||
unsigned long page_addr;
|
||||
unsigned long end;
|
||||
int page_index;
|
||||
|
||||
end = PAGE_ALIGN(buffer->user_data + size);
|
||||
page_addr = buffer->user_data;
|
||||
for (; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
page_index = (page_addr - alloc->vm_start) / PAGE_SIZE;
|
||||
if (!alloc->pages[page_index] ||
|
||||
!list_empty(page_to_lru(alloc->pages[page_index]))) {
|
||||
kunit_err(test, "expect alloc but is %s at page index %d\n",
|
||||
alloc->pages[page_index] ?
|
||||
"lru" : "free", page_index);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned long binder_alloc_test_alloc_buf(struct kunit *test,
|
||||
struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffers[],
|
||||
size_t *sizes, int *seq)
|
||||
{
|
||||
unsigned long failures = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
|
||||
if (IS_ERR(buffers[i]) ||
|
||||
!check_buffer_pages_allocated(test, alloc, buffers[i], sizes[i]))
|
||||
failures++;
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
static unsigned long binder_alloc_test_free_buf(struct kunit *test,
|
||||
struct binder_alloc *alloc,
|
||||
struct binder_buffer *buffers[],
|
||||
size_t *sizes, int *seq, size_t end)
|
||||
{
|
||||
unsigned long failures = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BUFFER_NUM; i++)
|
||||
binder_alloc_free_buf(alloc, buffers[seq[i]]);
|
||||
|
||||
for (i = 0; i <= (end - 1) / PAGE_SIZE; i++) {
|
||||
if (list_empty(page_to_lru(alloc->pages[i]))) {
|
||||
kunit_err(test, "expect lru but is %s at page index %d\n",
|
||||
alloc->pages[i] ? "alloc" : "free", i);
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
static unsigned long binder_alloc_test_free_page(struct kunit *test,
|
||||
struct binder_alloc *alloc)
|
||||
{
|
||||
unsigned long failures = 0;
|
||||
unsigned long count;
|
||||
int i;
|
||||
|
||||
while ((count = list_lru_count(alloc->freelist))) {
|
||||
list_lru_walk(alloc->freelist, binder_alloc_free_page,
|
||||
NULL, count);
|
||||
}
|
||||
|
||||
for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) {
|
||||
if (alloc->pages[i]) {
|
||||
kunit_err(test, "expect free but is %s at page index %d\n",
|
||||
list_empty(page_to_lru(alloc->pages[i])) ?
|
||||
"alloc" : "lru", i);
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
/* Executes one full test run for the given test case. */
|
||||
static bool binder_alloc_test_alloc_free(struct kunit *test,
|
||||
struct binder_alloc *alloc,
|
||||
struct binder_alloc_test_case_info *tc,
|
||||
size_t end)
|
||||
{
|
||||
unsigned long pages = PAGE_ALIGN(end) / PAGE_SIZE;
|
||||
struct binder_buffer *buffers[BUFFER_NUM];
|
||||
unsigned long failures;
|
||||
bool failed = false;
|
||||
|
||||
failures = binder_alloc_test_alloc_buf(test, alloc, buffers,
|
||||
tc->buffer_sizes,
|
||||
tc->free_sequence);
|
||||
failed = failed || failures;
|
||||
KUNIT_EXPECT_EQ_MSG(test, failures, 0,
|
||||
"Initial allocation failed: %lu/%u buffers with errors",
|
||||
failures, BUFFER_NUM);
|
||||
|
||||
failures = binder_alloc_test_free_buf(test, alloc, buffers,
|
||||
tc->buffer_sizes,
|
||||
tc->free_sequence, end);
|
||||
failed = failed || failures;
|
||||
KUNIT_EXPECT_EQ_MSG(test, failures, 0,
|
||||
"Initial buffers not freed correctly: %lu/%lu pages not on lru list",
|
||||
failures, pages);
|
||||
|
||||
/* Allocate from lru. */
|
||||
failures = binder_alloc_test_alloc_buf(test, alloc, buffers,
|
||||
tc->buffer_sizes,
|
||||
tc->free_sequence);
|
||||
failed = failed || failures;
|
||||
KUNIT_EXPECT_EQ_MSG(test, failures, 0,
|
||||
"Reallocation failed: %lu/%u buffers with errors",
|
||||
failures, BUFFER_NUM);
|
||||
|
||||
failures = list_lru_count(alloc->freelist);
|
||||
failed = failed || failures;
|
||||
KUNIT_EXPECT_EQ_MSG(test, failures, 0,
|
||||
"lru list should be empty after reallocation but still has %lu pages",
|
||||
failures);
|
||||
|
||||
failures = binder_alloc_test_free_buf(test, alloc, buffers,
|
||||
tc->buffer_sizes,
|
||||
tc->free_sequence, end);
|
||||
failed = failed || failures;
|
||||
KUNIT_EXPECT_EQ_MSG(test, failures, 0,
|
||||
"Reallocated buffers not freed correctly: %lu/%lu pages not on lru list",
|
||||
failures, pages);
|
||||
|
||||
failures = binder_alloc_test_free_page(test, alloc);
|
||||
failed = failed || failures;
|
||||
KUNIT_EXPECT_EQ_MSG(test, failures, 0,
|
||||
"Failed to clean up allocated pages: %lu/%lu pages still installed",
|
||||
failures, (alloc->buffer_size / PAGE_SIZE));
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
static bool is_dup(int *seq, int index, int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < index; i++) {
|
||||
if (seq[i] == val)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Generate BUFFER_NUM factorial free orders. */
|
||||
static void permute_frees(struct kunit *test, struct binder_alloc *alloc,
|
||||
struct binder_alloc_test_case_info *tc,
|
||||
unsigned long *runs, unsigned long *failures,
|
||||
int index, size_t end)
|
||||
{
|
||||
bool case_failed;
|
||||
int i;
|
||||
|
||||
if (index == BUFFER_NUM) {
|
||||
DECLARE_SEQ_BUF(freeseq_sb, FREESEQ_BUFLEN);
|
||||
|
||||
case_failed = binder_alloc_test_alloc_free(test, alloc, tc, end);
|
||||
*runs += 1;
|
||||
*failures += case_failed;
|
||||
|
||||
if (case_failed || PRINT_ALL_CASES) {
|
||||
stringify_free_seq(test, tc->free_sequence,
|
||||
&freeseq_sb);
|
||||
kunit_err(test, "case %lu: [%s] | %s - %s - %s", *runs,
|
||||
case_failed ? "FAILED" : "PASSED",
|
||||
tc->front_pages ? "front" : "back ",
|
||||
seq_buf_str(&tc->alignments_sb),
|
||||
seq_buf_str(&freeseq_sb));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
if (is_dup(tc->free_sequence, index, i))
|
||||
continue;
|
||||
tc->free_sequence[index] = i;
|
||||
permute_frees(test, alloc, tc, runs, failures, index + 1, end);
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_buf_sizes(struct kunit *test,
|
||||
struct binder_alloc *alloc,
|
||||
struct binder_alloc_test_case_info *tc,
|
||||
size_t *end_offset, unsigned long *runs,
|
||||
unsigned long *failures)
|
||||
{
|
||||
size_t last_offset, offset = 0;
|
||||
size_t front_sizes[BUFFER_NUM];
|
||||
size_t back_sizes[BUFFER_NUM];
|
||||
int seq[BUFFER_NUM] = {0};
|
||||
int i;
|
||||
|
||||
tc->free_sequence = seq;
|
||||
for (i = 0; i < BUFFER_NUM; i++) {
|
||||
last_offset = offset;
|
||||
offset = end_offset[i];
|
||||
front_sizes[i] = offset - last_offset;
|
||||
back_sizes[BUFFER_NUM - i - 1] = front_sizes[i];
|
||||
}
|
||||
back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1];
|
||||
|
||||
/*
|
||||
* Buffers share the first or last few pages.
|
||||
* Only BUFFER_NUM - 1 buffer sizes are adjustable since
|
||||
* we need one giant buffer before getting to the last page.
|
||||
*/
|
||||
tc->front_pages = true;
|
||||
tc->buffer_sizes = front_sizes;
|
||||
permute_frees(test, alloc, tc, runs, failures, 0,
|
||||
end_offset[BUFFER_NUM - 1]);
|
||||
|
||||
tc->front_pages = false;
|
||||
tc->buffer_sizes = back_sizes;
|
||||
permute_frees(test, alloc, tc, runs, failures, 0, alloc->buffer_size);
|
||||
}
|
||||
|
||||
static void gen_buf_offsets(struct kunit *test, struct binder_alloc *alloc,
|
||||
size_t *end_offset, int *alignments,
|
||||
unsigned long *runs, unsigned long *failures,
|
||||
int index)
|
||||
{
|
||||
size_t end, prev;
|
||||
int align;
|
||||
|
||||
if (index == BUFFER_NUM) {
|
||||
struct binder_alloc_test_case_info tc = {0};
|
||||
|
||||
seq_buf_init(&tc.alignments_sb, tc.alignments,
|
||||
ALIGNMENTS_BUFLEN);
|
||||
stringify_alignments(test, alignments, &tc.alignments_sb);
|
||||
|
||||
gen_buf_sizes(test, alloc, &tc, end_offset, runs, failures);
|
||||
return;
|
||||
}
|
||||
prev = index == 0 ? 0 : end_offset[index - 1];
|
||||
end = prev;
|
||||
|
||||
BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE);
|
||||
|
||||
for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) {
|
||||
if (align % 2)
|
||||
end = ALIGN(end, PAGE_SIZE);
|
||||
else
|
||||
end += BUFFER_MIN_SIZE;
|
||||
end_offset[index] = end;
|
||||
alignments[index] = align;
|
||||
gen_buf_offsets(test, alloc, end_offset, alignments, runs,
|
||||
failures, index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
struct binder_alloc_test {
|
||||
struct binder_alloc alloc;
|
||||
struct list_lru binder_test_freelist;
|
||||
struct file *filp;
|
||||
unsigned long mmap_uaddr;
|
||||
};
|
||||
|
||||
static void binder_alloc_test_init_freelist(struct kunit *test)
|
||||
{
|
||||
struct binder_alloc_test *priv = test->priv;
|
||||
|
||||
KUNIT_EXPECT_PTR_EQ(test, priv->alloc.freelist,
|
||||
&priv->binder_test_freelist);
|
||||
}
|
||||
|
||||
static void binder_alloc_test_mmap(struct kunit *test)
|
||||
{
|
||||
struct binder_alloc_test *priv = test->priv;
|
||||
struct binder_alloc *alloc = &priv->alloc;
|
||||
struct binder_buffer *buf;
|
||||
struct rb_node *n;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, alloc->mapped, true);
|
||||
KUNIT_EXPECT_EQ(test, alloc->buffer_size, BINDER_MMAP_SIZE);
|
||||
|
||||
n = rb_first(&alloc->allocated_buffers);
|
||||
KUNIT_EXPECT_PTR_EQ(test, n, NULL);
|
||||
|
||||
n = rb_first(&alloc->free_buffers);
|
||||
buf = rb_entry(n, struct binder_buffer, rb_node);
|
||||
KUNIT_EXPECT_EQ(test, binder_alloc_buffer_size(alloc, buf),
|
||||
BINDER_MMAP_SIZE);
|
||||
KUNIT_EXPECT_TRUE(test, list_is_last(&buf->entry, &alloc->buffers));
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_alloc_exhaustive_test() - Exhaustively test alloc and free of buffer pages.
|
||||
* @test: The test context object.
|
||||
*
|
||||
* Allocate BUFFER_NUM buffers to cover all page alignment cases,
|
||||
* then free them in all orders possible. Check that pages are
|
||||
* correctly allocated, put onto lru when buffers are freed, and
|
||||
* are freed when binder_alloc_free_page() is called.
|
||||
*/
|
||||
static void binder_alloc_exhaustive_test(struct kunit *test)
|
||||
{
|
||||
struct binder_alloc_test *priv = test->priv;
|
||||
size_t end_offset[BUFFER_NUM];
|
||||
int alignments[BUFFER_NUM];
|
||||
unsigned long failures = 0;
|
||||
unsigned long runs = 0;
|
||||
|
||||
gen_buf_offsets(test, &priv->alloc, end_offset, alignments, &runs,
|
||||
&failures, 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, runs, TOTAL_EXHAUSTIVE_CASES);
|
||||
KUNIT_EXPECT_EQ(test, failures, 0);
|
||||
}
|
||||
|
||||
/* ===== End test cases ===== */
|
||||
|
||||
static void binder_alloc_test_vma_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct binder_alloc *alloc = vma->vm_private_data;
|
||||
|
||||
binder_alloc_vma_close(alloc);
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct binder_alloc_test_vm_ops = {
|
||||
.close = binder_alloc_test_vma_close,
|
||||
.fault = binder_vm_fault,
|
||||
};
|
||||
|
||||
static int binder_alloc_test_mmap_handler(struct file *filp,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct binder_alloc *alloc = filp->private_data;
|
||||
|
||||
vm_flags_mod(vma, VM_DONTCOPY | VM_MIXEDMAP, VM_MAYWRITE);
|
||||
|
||||
vma->vm_ops = &binder_alloc_test_vm_ops;
|
||||
vma->vm_private_data = alloc;
|
||||
|
||||
return binder_alloc_mmap_handler(alloc, vma);
|
||||
}
|
||||
|
||||
static const struct file_operations binder_alloc_test_fops = {
|
||||
.mmap = binder_alloc_test_mmap_handler,
|
||||
};
|
||||
|
||||
static int binder_alloc_test_init(struct kunit *test)
|
||||
{
|
||||
struct binder_alloc_test *priv;
|
||||
int ret;
|
||||
|
||||
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
test->priv = priv;
|
||||
|
||||
ret = list_lru_init(&priv->binder_test_freelist);
|
||||
if (ret) {
|
||||
kunit_err(test, "Failed to initialize test freelist\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* __binder_alloc_init requires mm to be attached */
|
||||
ret = kunit_attach_mm();
|
||||
if (ret) {
|
||||
kunit_err(test, "Failed to attach mm\n");
|
||||
return ret;
|
||||
}
|
||||
__binder_alloc_init(&priv->alloc, &priv->binder_test_freelist);
|
||||
|
||||
priv->filp = anon_inode_getfile("binder_alloc_kunit",
|
||||
&binder_alloc_test_fops, &priv->alloc,
|
||||
O_RDWR | O_CLOEXEC);
|
||||
if (IS_ERR_OR_NULL(priv->filp)) {
|
||||
kunit_err(test, "Failed to open binder alloc test driver file\n");
|
||||
return priv->filp ? PTR_ERR(priv->filp) : -ENOMEM;
|
||||
}
|
||||
|
||||
priv->mmap_uaddr = kunit_vm_mmap(test, priv->filp, 0, BINDER_MMAP_SIZE,
|
||||
PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
|
||||
0);
|
||||
if (!priv->mmap_uaddr) {
|
||||
kunit_err(test, "Could not map the test's transaction memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void binder_alloc_test_exit(struct kunit *test)
|
||||
{
|
||||
struct binder_alloc_test *priv = test->priv;
|
||||
|
||||
/* Close the backing file to make sure binder_alloc_vma_close runs */
|
||||
if (!IS_ERR_OR_NULL(priv->filp))
|
||||
fput(priv->filp);
|
||||
|
||||
if (priv->alloc.mm)
|
||||
binder_alloc_deferred_release(&priv->alloc);
|
||||
|
||||
/* Make sure freelist is empty */
|
||||
KUNIT_EXPECT_EQ(test, list_lru_count(&priv->binder_test_freelist), 0);
|
||||
list_lru_destroy(&priv->binder_test_freelist);
|
||||
}
|
||||
|
||||
static struct kunit_case binder_alloc_test_cases[] = {
|
||||
KUNIT_CASE(binder_alloc_test_init_freelist),
|
||||
KUNIT_CASE(binder_alloc_test_mmap),
|
||||
KUNIT_CASE(binder_alloc_exhaustive_test),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite binder_alloc_test_suite = {
|
||||
.name = "binder_alloc",
|
||||
.test_cases = binder_alloc_test_cases,
|
||||
.init = binder_alloc_test_init,
|
||||
.exit = binder_alloc_test_exit,
|
||||
};
|
||||
|
||||
kunit_test_suite(binder_alloc_test_suite);
|
||||
|
||||
MODULE_AUTHOR("Tiffany Yang <ynaffit@google.com>");
|
||||
MODULE_DESCRIPTION("Binder Alloc KUnit tests");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -31,8 +31,8 @@ int mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
|||
int ret;
|
||||
|
||||
for (i = 0; i < img_info->entries - 1; i++, mhi_buf++, bhi_vec++) {
|
||||
bhi_vec->dma_addr = mhi_buf->dma_addr;
|
||||
bhi_vec->size = mhi_buf->len;
|
||||
bhi_vec->dma_addr = cpu_to_le64(mhi_buf->dma_addr);
|
||||
bhi_vec->size = cpu_to_le64(mhi_buf->len);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "BHIe programming for RDDM\n");
|
||||
|
@ -431,8 +431,8 @@ static void mhi_firmware_copy_bhie(struct mhi_controller *mhi_cntrl,
|
|||
while (remainder) {
|
||||
to_cpy = min(remainder, mhi_buf->len);
|
||||
memcpy(mhi_buf->buf, buf, to_cpy);
|
||||
bhi_vec->dma_addr = mhi_buf->dma_addr;
|
||||
bhi_vec->size = to_cpy;
|
||||
bhi_vec->dma_addr = cpu_to_le64(mhi_buf->dma_addr);
|
||||
bhi_vec->size = cpu_to_le64(to_cpy);
|
||||
|
||||
buf += to_cpy;
|
||||
remainder -= to_cpy;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/mhi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include "internal.h"
|
||||
|
||||
static int mhi_debugfs_states_show(struct seq_file *m, void *d)
|
||||
|
@ -22,7 +23,7 @@ static int mhi_debugfs_states_show(struct seq_file *m, void *d)
|
|||
mhi_is_active(mhi_cntrl) ? "Active" : "Inactive",
|
||||
mhi_state_str(mhi_cntrl->dev_state),
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee),
|
||||
mhi_cntrl->wake_set ? "true" : "false");
|
||||
str_true_false(mhi_cntrl->wake_set));
|
||||
|
||||
/* counters */
|
||||
seq_printf(m, "M0: %u M2: %u M3: %u", mhi_cntrl->M0, mhi_cntrl->M2,
|
||||
|
|
|
@ -176,7 +176,7 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl)
|
||||
static void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
int i;
|
||||
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
|
||||
|
@ -191,7 +191,7 @@ void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl)
|
|||
free_irq(mhi_cntrl->irq[0], mhi_cntrl);
|
||||
}
|
||||
|
||||
int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
|
||||
static int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
|
||||
struct device *dev = &mhi_cntrl->mhi_dev->dev;
|
||||
|
@ -254,7 +254,7 @@ error_request:
|
|||
return ret;
|
||||
}
|
||||
|
||||
void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
||||
static void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
int i;
|
||||
struct mhi_ctxt *mhi_ctxt = mhi_cntrl->mhi_ctxt;
|
||||
|
@ -299,7 +299,7 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
|||
mhi_cntrl->mhi_ctxt = NULL;
|
||||
}
|
||||
|
||||
int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
||||
static int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_ctxt *mhi_ctxt;
|
||||
struct mhi_chan_ctxt *chan_ctxt;
|
||||
|
|
|
@ -25,8 +25,8 @@ struct mhi_ctxt {
|
|||
};
|
||||
|
||||
struct bhi_vec_entry {
|
||||
u64 dma_addr;
|
||||
u64 size;
|
||||
__le64 dma_addr;
|
||||
__le64 size;
|
||||
};
|
||||
|
||||
enum mhi_fw_load_type {
|
||||
|
@ -383,19 +383,12 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
|
|||
|
||||
/* Initialization methods */
|
||||
int mhi_init_mmio(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *img_info);
|
||||
void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/* Automatically allocate and queue inbound buffers */
|
||||
#define MHI_CH_INBOUND_ALLOC_BUFS BIT(0)
|
||||
int mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan, unsigned int flags);
|
||||
|
||||
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan);
|
||||
void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
||||
|
|
|
@ -602,7 +602,7 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
|
|||
{
|
||||
dma_addr_t ptr = MHI_TRE_GET_EV_PTR(event);
|
||||
struct mhi_ring_element *local_rp, *ev_tre;
|
||||
void *dev_rp;
|
||||
void *dev_rp, *next_rp;
|
||||
struct mhi_buf_info *buf_info;
|
||||
u16 xfer_len;
|
||||
|
||||
|
@ -621,6 +621,16 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
|
|||
result.dir = mhi_chan->dir;
|
||||
|
||||
local_rp = tre_ring->rp;
|
||||
|
||||
next_rp = local_rp + 1;
|
||||
if (next_rp >= tre_ring->base + tre_ring->len)
|
||||
next_rp = tre_ring->base;
|
||||
if (dev_rp != next_rp && !MHI_TRE_DATA_GET_CHAIN(local_rp)) {
|
||||
dev_err(&mhi_cntrl->mhi_dev->dev,
|
||||
"Event element points to an unexpected TRE\n");
|
||||
break;
|
||||
}
|
||||
|
||||
while (local_rp != dev_rp) {
|
||||
buf_info = buf_ring->rp;
|
||||
/* If it's the last TRE, get length from the event */
|
||||
|
@ -1435,7 +1445,7 @@ exit_unprepare_channel:
|
|||
mutex_unlock(&mhi_chan->mutex);
|
||||
}
|
||||
|
||||
int mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
|
||||
static int mhi_prepare_channel(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan, unsigned int flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
* @mru_default: default MRU size for MBIM network packets
|
||||
* @sideband_wake: Devices using dedicated sideband GPIO for wakeup instead
|
||||
* of inband wake support (such as sdx24)
|
||||
* @no_m3: M3 not supported
|
||||
*/
|
||||
struct mhi_pci_dev_info {
|
||||
const struct mhi_controller_config *config;
|
||||
|
@ -54,6 +55,7 @@ struct mhi_pci_dev_info {
|
|||
unsigned int dma_data_width;
|
||||
unsigned int mru_default;
|
||||
bool sideband_wake;
|
||||
bool no_m3;
|
||||
};
|
||||
|
||||
#define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \
|
||||
|
@ -295,6 +297,7 @@ static const struct mhi_pci_dev_info mhi_qcom_qdu100_info = {
|
|||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.sideband_wake = false,
|
||||
.no_m3 = true,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_qcom_sa8775p_channels[] = {
|
||||
|
@ -490,6 +493,23 @@ static const struct mhi_channel_config mhi_foxconn_sdx55_channels[] = {
|
|||
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_foxconn_sdx61_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 1),
|
||||
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 1),
|
||||
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL_FP(34, "FIREHOSE", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL_FP(35, "FIREHOSE", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_UL(50, "NMEA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(51, "NMEA", 32, 0),
|
||||
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2),
|
||||
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3),
|
||||
};
|
||||
|
||||
static struct mhi_event_config mhi_foxconn_sdx55_events[] = {
|
||||
MHI_EVENT_CONFIG_CTRL(0, 128),
|
||||
MHI_EVENT_CONFIG_DATA(1, 128),
|
||||
|
@ -506,6 +526,15 @@ static const struct mhi_controller_config modem_foxconn_sdx55_config = {
|
|||
.event_cfg = mhi_foxconn_sdx55_events,
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config modem_foxconn_sdx61_config = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 20000,
|
||||
.num_channels = ARRAY_SIZE(mhi_foxconn_sdx61_channels),
|
||||
.ch_cfg = mhi_foxconn_sdx61_channels,
|
||||
.num_events = ARRAY_SIZE(mhi_foxconn_sdx55_events),
|
||||
.event_cfg = mhi_foxconn_sdx55_events,
|
||||
};
|
||||
|
||||
static const struct mhi_controller_config modem_foxconn_sdx72_config = {
|
||||
.max_channels = 128,
|
||||
.timeout_ms = 20000,
|
||||
|
@ -593,8 +622,8 @@ static const struct mhi_pci_dev_info mhi_foxconn_dw5932e_info = {
|
|||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_foxconn_t99w515_info = {
|
||||
.name = "foxconn-t99w515",
|
||||
static const struct mhi_pci_dev_info mhi_foxconn_t99w640_info = {
|
||||
.name = "foxconn-t99w640",
|
||||
.edl = "qcom/sdx72m/foxconn/edl.mbn",
|
||||
.edl_trigger = true,
|
||||
.config = &modem_foxconn_sdx72_config,
|
||||
|
@ -615,6 +644,17 @@ static const struct mhi_pci_dev_info mhi_foxconn_dw5934e_info = {
|
|||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_foxconn_t99w696_info = {
|
||||
.name = "foxconn-t99w696",
|
||||
.edl = "qcom/sdx61/foxconn/prog_firehose_lite.elf",
|
||||
.edl_trigger = true,
|
||||
.config = &modem_foxconn_sdx61_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.mru_default = 32768,
|
||||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
static const struct mhi_channel_config mhi_mv3x_channels[] = {
|
||||
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0),
|
||||
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0),
|
||||
|
@ -695,6 +735,7 @@ static const struct mhi_pci_dev_info mhi_sierra_em919x_info = {
|
|||
.config = &modem_sierra_em919x_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.mru_default = 32768,
|
||||
.sideband_wake = false,
|
||||
};
|
||||
|
||||
|
@ -818,6 +859,16 @@ static const struct mhi_pci_dev_info mhi_telit_fn920c04_info = {
|
|||
.edl_trigger = true,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_telit_fn990b40_info = {
|
||||
.name = "telit-fn990b40",
|
||||
.config = &modem_telit_fn920c04_config,
|
||||
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
|
||||
.dma_data_width = 32,
|
||||
.sideband_wake = false,
|
||||
.mru_default = 32768,
|
||||
.edl_trigger = true,
|
||||
};
|
||||
|
||||
static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = {
|
||||
.name = "netprisma-lcur57",
|
||||
.edl = "qcom/prog_firehose_sdx24.mbn",
|
||||
|
@ -852,6 +903,9 @@ static const struct pci_device_id mhi_pci_id_table[] = {
|
|||
/* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200),
|
||||
.driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info },
|
||||
/* EM929x (sdx65), use the same configuration as EM919x */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x18d7, 0x0301),
|
||||
.driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info },
|
||||
/* Telit FN980 hardware revision v1 */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x1C5D, 0x2000),
|
||||
.driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v1_info },
|
||||
|
@ -863,8 +917,26 @@ static const struct pci_device_id mhi_pci_id_table[] = {
|
|||
/* Telit FE990A */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2015),
|
||||
.driver_data = (kernel_ulong_t) &mhi_telit_fe990a_info },
|
||||
/* Foxconn T99W696.01, Lenovo Generic SKU */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe142),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
|
||||
/* Foxconn T99W696.02, Lenovo X1 Carbon SKU */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe143),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
|
||||
/* Foxconn T99W696.03, Lenovo X1 2in1 SKU */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe144),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
|
||||
/* Foxconn T99W696.04, Lenovo PRC SKU */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe145),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
|
||||
/* Foxconn T99W696.00, Foxconn SKU */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, PCI_VENDOR_ID_FOXCONN, 0xe146),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w696_info },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
|
||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
|
||||
/* Telit FN990B40 (sdx72) */
|
||||
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0309, 0x1c5d, 0x201a),
|
||||
.driver_data = (kernel_ulong_t) &mhi_telit_fn990b40_info },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309),
|
||||
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info },
|
||||
/* QDU100, x100-DU */
|
||||
|
@ -920,9 +992,9 @@ static const struct pci_device_id mhi_pci_id_table[] = {
|
|||
/* DW5932e (sdx62), Non-eSIM */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0f9),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_dw5932e_info },
|
||||
/* T99W515 (sdx72) */
|
||||
/* T99W640 (sdx72) */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe118),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w515_info },
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w640_info },
|
||||
/* DW5934e(sdx72), With eSIM */
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe11d),
|
||||
.driver_data = (kernel_ulong_t) &mhi_foxconn_dw5934e_info },
|
||||
|
@ -1306,8 +1378,8 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
/* start health check */
|
||||
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
|
||||
|
||||
/* Only allow runtime-suspend if PME capable (for wakeup) */
|
||||
if (pci_pme_capable(pdev, PCI_D3hot)) {
|
||||
/* Allow runtime suspend only if both PME from D3Hot and M3 are supported */
|
||||
if (pci_pme_capable(pdev, PCI_D3hot) && !(info->no_m3)) {
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
|
|
|
@ -737,8 +737,7 @@ static int moxtet_irq_setup(struct moxtet *moxtet)
|
|||
{
|
||||
int i, ret;
|
||||
|
||||
moxtet->irq.domain = irq_domain_create_simple(of_fwnode_handle(moxtet->dev->of_node),
|
||||
MOXTET_NIRQS, 0,
|
||||
moxtet->irq.domain = irq_domain_create_simple(dev_fwnode(moxtet->dev), MOXTET_NIRQS, 0,
|
||||
&moxtet_irq_domain, moxtet);
|
||||
if (moxtet->irq.domain == NULL) {
|
||||
dev_err(moxtet->dev, "Could not add IRQ domain\n");
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
config CDX_BUS
|
||||
bool "CDX Bus driver"
|
||||
depends on OF && ARM64
|
||||
depends on OF && ARM64 || COMPILE_TEST
|
||||
select GENERIC_MSI_IRQ
|
||||
help
|
||||
Driver to enable Composable DMA Transfer(CDX) Bus. CDX bus
|
||||
exposes Fabric devices which uses composable DMA IP to the
|
||||
|
|
|
@ -9,6 +9,7 @@ if CDX_BUS
|
|||
|
||||
config CDX_CONTROLLER
|
||||
tristate "CDX bus controller"
|
||||
depends on HAS_DMA
|
||||
select GENERIC_MSI_IRQ
|
||||
select REMOTEPROC
|
||||
select RPMSG
|
||||
|
|
|
@ -195,19 +195,16 @@ static int xlnx_cdx_probe(struct platform_device *pdev)
|
|||
/* Create MSI domain */
|
||||
cdx->msi_domain = cdx_msi_domain_init(&pdev->dev);
|
||||
if (!cdx->msi_domain) {
|
||||
dev_err(&pdev->dev, "cdx_msi_domain_init() failed");
|
||||
ret = -ENODEV;
|
||||
ret = dev_err_probe(&pdev->dev, -ENODEV, "cdx_msi_domain_init() failed");
|
||||
goto cdx_msi_fail;
|
||||
}
|
||||
|
||||
ret = cdx_setup_rpmsg(pdev);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Failed to register CDX RPMsg transport\n");
|
||||
dev_err_probe(&pdev->dev, ret, "Failed to register CDX RPMsg transport\n");
|
||||
goto cdx_rpmsg_fail;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "Successfully registered CDX controller with RPMsg as transport\n");
|
||||
return 0;
|
||||
|
||||
cdx_rpmsg_fail:
|
||||
|
@ -246,31 +243,13 @@ MODULE_DEVICE_TABLE(of, cdx_match_table);
|
|||
static struct platform_driver cdx_pdriver = {
|
||||
.driver = {
|
||||
.name = "cdx-controller",
|
||||
.pm = NULL,
|
||||
.of_match_table = cdx_match_table,
|
||||
},
|
||||
.probe = xlnx_cdx_probe,
|
||||
.remove = xlnx_cdx_remove,
|
||||
};
|
||||
|
||||
static int __init cdx_controller_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&cdx_pdriver);
|
||||
if (ret)
|
||||
pr_err("platform_driver_register() failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit cdx_controller_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cdx_pdriver);
|
||||
}
|
||||
|
||||
module_init(cdx_controller_init);
|
||||
module_exit(cdx_controller_exit);
|
||||
module_platform_driver(cdx_pdriver);
|
||||
|
||||
MODULE_AUTHOR("AMD Inc.");
|
||||
MODULE_DESCRIPTION("CDX controller for AMD devices");
|
||||
|
|
|
@ -237,7 +237,7 @@ config APPLICOM
|
|||
|
||||
config SONYPI
|
||||
tristate "Sony Vaio Programmable I/O Control Device support"
|
||||
depends on X86_32 && PCI && INPUT
|
||||
depends on X86_32 && PCI && INPUT && HAS_IOPORT
|
||||
depends on ACPI_EC || !ACPI
|
||||
help
|
||||
This driver enables access to the Sony Programmable I/O Control
|
||||
|
|
|
@ -289,15 +289,15 @@ EXPORT_SYMBOL(misc_deregister);
|
|||
static int __init misc_init(void)
|
||||
{
|
||||
int err;
|
||||
struct proc_dir_entry *ret;
|
||||
struct proc_dir_entry *misc_proc_file;
|
||||
|
||||
ret = proc_create_seq("misc", 0, NULL, &misc_seq_ops);
|
||||
misc_proc_file = proc_create_seq("misc", 0, NULL, &misc_seq_ops);
|
||||
err = class_register(&misc_class);
|
||||
if (err)
|
||||
goto fail_remove;
|
||||
|
||||
err = -EIO;
|
||||
if (__register_chrdev(MISC_MAJOR, 0, MINORMASK + 1, "misc", &misc_fops))
|
||||
err = __register_chrdev(MISC_MAJOR, 0, MINORMASK + 1, "misc", &misc_fops);
|
||||
if (err < 0)
|
||||
goto fail_printk;
|
||||
return 0;
|
||||
|
||||
|
@ -305,7 +305,7 @@ fail_printk:
|
|||
pr_err("unable to get major %d for misc devices\n", MISC_MAJOR);
|
||||
class_unregister(&misc_class);
|
||||
fail_remove:
|
||||
if (ret)
|
||||
if (misc_proc_file)
|
||||
remove_proc_entry("misc", NULL);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -787,6 +787,7 @@ static int is_device_busy(struct comedi_device *dev)
|
|||
struct comedi_subdevice *s;
|
||||
int i;
|
||||
|
||||
lockdep_assert_held_write(&dev->attach_lock);
|
||||
lockdep_assert_held(&dev->mutex);
|
||||
if (!dev->attached)
|
||||
return 0;
|
||||
|
@ -795,7 +796,16 @@ static int is_device_busy(struct comedi_device *dev)
|
|||
s = &dev->subdevices[i];
|
||||
if (s->busy)
|
||||
return 1;
|
||||
if (s->async && comedi_buf_is_mmapped(s))
|
||||
if (!s->async)
|
||||
continue;
|
||||
if (comedi_buf_is_mmapped(s))
|
||||
return 1;
|
||||
/*
|
||||
* There may be tasks still waiting on the subdevice's wait
|
||||
* queue, although they should already be about to be removed
|
||||
* from it since the subdevice has no active async command.
|
||||
*/
|
||||
if (wq_has_sleeper(&s->async->wait_head))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -825,15 +835,22 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
|
|||
return -EPERM;
|
||||
|
||||
if (!arg) {
|
||||
if (is_device_busy(dev))
|
||||
return -EBUSY;
|
||||
if (dev->attached) {
|
||||
struct module *driver_module = dev->driver->module;
|
||||
int rc = 0;
|
||||
|
||||
comedi_device_detach(dev);
|
||||
module_put(driver_module);
|
||||
if (dev->attached) {
|
||||
down_write(&dev->attach_lock);
|
||||
if (is_device_busy(dev)) {
|
||||
rc = -EBUSY;
|
||||
} else {
|
||||
struct module *driver_module =
|
||||
dev->driver->module;
|
||||
|
||||
comedi_device_detach_locked(dev);
|
||||
module_put(driver_module);
|
||||
}
|
||||
up_write(&dev->attach_lock);
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (copy_from_user(&it, arg, sizeof(it)))
|
||||
|
|
|
@ -50,6 +50,7 @@ extern struct mutex comedi_drivers_list_lock;
|
|||
int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
|
||||
struct comedi_insn *insn, unsigned int *data);
|
||||
|
||||
void comedi_device_detach_locked(struct comedi_device *dev);
|
||||
void comedi_device_detach(struct comedi_device *dev);
|
||||
int comedi_device_attach(struct comedi_device *dev,
|
||||
struct comedi_devconfig *it);
|
||||
|
|
|
@ -158,7 +158,7 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev)
|
|||
int i;
|
||||
struct comedi_subdevice *s;
|
||||
|
||||
lockdep_assert_held(&dev->attach_lock);
|
||||
lockdep_assert_held_write(&dev->attach_lock);
|
||||
lockdep_assert_held(&dev->mutex);
|
||||
if (dev->subdevices) {
|
||||
for (i = 0; i < dev->n_subdevices; i++) {
|
||||
|
@ -196,16 +196,23 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev)
|
|||
comedi_clear_hw_dev(dev);
|
||||
}
|
||||
|
||||
void comedi_device_detach(struct comedi_device *dev)
|
||||
void comedi_device_detach_locked(struct comedi_device *dev)
|
||||
{
|
||||
lockdep_assert_held_write(&dev->attach_lock);
|
||||
lockdep_assert_held(&dev->mutex);
|
||||
comedi_device_cancel_all(dev);
|
||||
down_write(&dev->attach_lock);
|
||||
dev->attached = false;
|
||||
dev->detach_count++;
|
||||
if (dev->driver)
|
||||
dev->driver->detach(dev);
|
||||
comedi_device_detach_cleanup(dev);
|
||||
}
|
||||
|
||||
void comedi_device_detach(struct comedi_device *dev)
|
||||
{
|
||||
lockdep_assert_held(&dev->mutex);
|
||||
down_write(&dev->attach_lock);
|
||||
comedi_device_detach_locked(dev);
|
||||
up_write(&dev->attach_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -406,7 +406,7 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr, struct sg_table *sgt)
|
|||
}
|
||||
|
||||
priv->dma_nelms =
|
||||
dma_map_sg(mgr->dev.parent, sgt->sgl, sgt->nents, DMA_TO_DEVICE);
|
||||
dma_map_sgtable(mgr->dev.parent, sgt, DMA_TO_DEVICE, 0);
|
||||
if (priv->dma_nelms == 0) {
|
||||
dev_err(&mgr->dev, "Unable to DMA map (TO_DEVICE)\n");
|
||||
return -ENOMEM;
|
||||
|
@ -478,7 +478,7 @@ out_clk:
|
|||
clk_disable(priv->clk);
|
||||
|
||||
out_free:
|
||||
dma_unmap_sg(mgr->dev.parent, sgt->sgl, sgt->nents, DMA_TO_DEVICE);
|
||||
dma_unmap_sgtable(mgr->dev.parent, sgt, DMA_TO_DEVICE, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -1404,7 +1404,7 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(fsi_driver_unregister);
|
||||
|
||||
struct bus_type fsi_bus_type = {
|
||||
const struct bus_type fsi_bus_type = {
|
||||
.name = "fsi",
|
||||
.match = fsi_bus_match,
|
||||
};
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
#include <linux/irqflags.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/gpio/aspeed.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/genalloc.h>
|
||||
|
||||
#include "fsi-master.h"
|
||||
|
@ -1285,14 +1285,7 @@ static int fsi_master_acf_probe(struct platform_device *pdev)
|
|||
master->gpio_mux = gpio;
|
||||
|
||||
/* Grab the reserved memory region (use DMA API instead ?) */
|
||||
np = of_parse_phandle(mnode, "memory-region", 0);
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Didn't find reserved memory\n");
|
||||
rc = -EINVAL;
|
||||
goto err_free;
|
||||
}
|
||||
rc = of_address_to_resource(np, 0, &res);
|
||||
of_node_put(np);
|
||||
rc = of_reserved_mem_region_to_resource(mnode, 0, &res);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Couldn't address to resource for reserved memory\n");
|
||||
rc = -ENOMEM;
|
||||
|
|
|
@ -1039,9 +1039,12 @@ static const struct fw_upload_ops cc1352_bootloader_ops = {
|
|||
.cleanup = cc1352_cleanup
|
||||
};
|
||||
|
||||
/*
|
||||
* Must only be called from probe() as the devres resources allocated here
|
||||
* will only be released on driver detach.
|
||||
*/
|
||||
static int gb_fw_init(struct gb_beagleplay *bg)
|
||||
{
|
||||
int ret;
|
||||
struct fw_upload *fwl;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
|
@ -1060,29 +1063,17 @@ static int gb_fw_init(struct gb_beagleplay *bg)
|
|||
bg->bootloader_backdoor_gpio = desc;
|
||||
|
||||
desc = devm_gpiod_get(&bg->sd->dev, "reset", GPIOD_IN);
|
||||
if (IS_ERR(desc)) {
|
||||
ret = PTR_ERR(desc);
|
||||
goto free_boot;
|
||||
}
|
||||
if (IS_ERR(desc))
|
||||
return PTR_ERR(desc);
|
||||
bg->rst_gpio = desc;
|
||||
|
||||
fwl = firmware_upload_register(THIS_MODULE, &bg->sd->dev, "cc1352p7",
|
||||
&cc1352_bootloader_ops, bg);
|
||||
if (IS_ERR(fwl)) {
|
||||
ret = PTR_ERR(fwl);
|
||||
goto free_reset;
|
||||
}
|
||||
if (IS_ERR(fwl))
|
||||
return PTR_ERR(fwl);
|
||||
bg->fwl = fwl;
|
||||
|
||||
return 0;
|
||||
|
||||
free_reset:
|
||||
devm_gpiod_put(&bg->sd->dev, bg->rst_gpio);
|
||||
bg->rst_gpio = NULL;
|
||||
free_boot:
|
||||
devm_gpiod_put(&bg->sd->dev, bg->bootloader_backdoor_gpio);
|
||||
bg->bootloader_backdoor_gpio = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gb_fw_deinit(struct gb_beagleplay *bg)
|
||||
|
|
|
@ -18,10 +18,14 @@
|
|||
#define ADXL313_REG_SOFT_RESET 0x18
|
||||
#define ADXL313_REG_OFS_AXIS(index) (0x1E + (index))
|
||||
#define ADXL313_REG_THRESH_ACT 0x24
|
||||
#define ADXL313_REG_THRESH_INACT 0x25
|
||||
#define ADXL313_REG_TIME_INACT 0x26
|
||||
#define ADXL313_REG_ACT_INACT_CTL 0x27
|
||||
#define ADXL313_REG_BW_RATE 0x2C
|
||||
#define ADXL313_REG_POWER_CTL 0x2D
|
||||
#define ADXL313_REG_INT_ENABLE 0x2E
|
||||
#define ADXL313_REG_INT_MAP 0x2F
|
||||
#define ADXL313_REG_INT_SOURCE 0x30
|
||||
#define ADXL313_REG_DATA_FORMAT 0x31
|
||||
#define ADXL313_REG_DATA_AXIS(index) (0x32 + ((index) * 2))
|
||||
#define ADXL313_REG_FIFO_CTL 0x38
|
||||
|
@ -36,8 +40,10 @@
|
|||
#define ADXL313_RATE_MSK GENMASK(3, 0)
|
||||
#define ADXL313_RATE_BASE 6
|
||||
|
||||
#define ADXL313_POWER_CTL_MSK GENMASK(3, 2)
|
||||
#define ADXL313_MEASUREMENT_MODE BIT(3)
|
||||
#define ADXL313_POWER_CTL_MSK BIT(3)
|
||||
#define ADXL313_POWER_CTL_INACT_MSK GENMASK(5, 4)
|
||||
#define ADXL313_POWER_CTL_LINK BIT(5)
|
||||
#define ADXL313_POWER_CTL_AUTO_SLEEP BIT(4)
|
||||
|
||||
#define ADXL313_RANGE_MSK GENMASK(1, 0)
|
||||
#define ADXL313_RANGE_MAX 3
|
||||
|
@ -46,6 +52,25 @@
|
|||
#define ADXL313_SPI_3WIRE BIT(6)
|
||||
#define ADXL313_I2C_DISABLE BIT(6)
|
||||
|
||||
#define ADXL313_INT_OVERRUN BIT(0)
|
||||
#define ADXL313_INT_WATERMARK BIT(1)
|
||||
#define ADXL313_INT_INACTIVITY BIT(3)
|
||||
#define ADXL313_INT_ACTIVITY BIT(4)
|
||||
#define ADXL313_INT_DREADY BIT(7)
|
||||
|
||||
/* FIFO entries: how many values are stored in the FIFO */
|
||||
#define ADXL313_REG_FIFO_STATUS_ENTRIES_MSK GENMASK(5, 0)
|
||||
/* FIFO samples: number of samples needed for watermark (FIFO mode) */
|
||||
#define ADXL313_REG_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0)
|
||||
#define ADXL313_REG_FIFO_CTL_MODE_MSK GENMASK(7, 6)
|
||||
|
||||
#define ADXL313_FIFO_BYPASS 0
|
||||
#define ADXL313_FIFO_STREAM 2
|
||||
|
||||
#define ADXL313_FIFO_SIZE 32
|
||||
|
||||
#define ADXL313_NUM_AXIS 3
|
||||
|
||||
extern const struct regmap_access_table adxl312_readable_regs_table;
|
||||
extern const struct regmap_access_table adxl313_readable_regs_table;
|
||||
extern const struct regmap_access_table adxl314_readable_regs_table;
|
||||
|
@ -54,6 +79,8 @@ extern const struct regmap_access_table adxl312_writable_regs_table;
|
|||
extern const struct regmap_access_table adxl313_writable_regs_table;
|
||||
extern const struct regmap_access_table adxl314_writable_regs_table;
|
||||
|
||||
bool adxl313_is_volatile_reg(struct device *dev, unsigned int reg);
|
||||
|
||||
enum adxl313_device_type {
|
||||
ADXL312,
|
||||
ADXL313,
|
||||
|
@ -64,7 +91,9 @@ struct adxl313_data {
|
|||
struct regmap *regmap;
|
||||
const struct adxl313_chip_info *chip_info;
|
||||
struct mutex lock; /* lock to protect transf_buf */
|
||||
u8 watermark;
|
||||
__le16 transf_buf __aligned(IIO_DMA_MINALIGN);
|
||||
__le16 fifo_buf[ADXL313_NUM_AXIS * ADXL313_FIFO_SIZE + 1];
|
||||
};
|
||||
|
||||
struct adxl313_chip_info {
|
||||
|
|
|
@ -8,11 +8,62 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
|
||||
#include "adxl313.h"
|
||||
|
||||
#define ADXL313_INT_NONE U8_MAX
|
||||
#define ADXL313_INT1 1
|
||||
#define ADXL313_INT2 2
|
||||
|
||||
#define ADXL313_REG_XYZ_BASE ADXL313_REG_DATA_AXIS(0)
|
||||
|
||||
#define ADXL313_ACT_XYZ_EN GENMASK(6, 4)
|
||||
#define ADXL313_INACT_XYZ_EN GENMASK(2, 0)
|
||||
|
||||
#define ADXL313_REG_ACT_ACDC_MSK BIT(7)
|
||||
#define ADXL313_REG_INACT_ACDC_MSK BIT(3)
|
||||
#define ADXL313_COUPLING_DC 0
|
||||
#define ADXL313_COUPLING_AC 1
|
||||
|
||||
/* activity/inactivity */
|
||||
enum adxl313_activity_type {
|
||||
ADXL313_ACTIVITY,
|
||||
ADXL313_INACTIVITY,
|
||||
ADXL313_ACTIVITY_AC,
|
||||
ADXL313_INACTIVITY_AC,
|
||||
};
|
||||
|
||||
static const unsigned int adxl313_act_int_reg[] = {
|
||||
[ADXL313_ACTIVITY] = ADXL313_INT_ACTIVITY,
|
||||
[ADXL313_INACTIVITY] = ADXL313_INT_INACTIVITY,
|
||||
[ADXL313_ACTIVITY_AC] = ADXL313_INT_ACTIVITY,
|
||||
[ADXL313_INACTIVITY_AC] = ADXL313_INT_INACTIVITY,
|
||||
};
|
||||
|
||||
static const unsigned int adxl313_act_thresh_reg[] = {
|
||||
[ADXL313_ACTIVITY] = ADXL313_REG_THRESH_ACT,
|
||||
[ADXL313_INACTIVITY] = ADXL313_REG_THRESH_INACT,
|
||||
[ADXL313_ACTIVITY_AC] = ADXL313_REG_THRESH_ACT,
|
||||
[ADXL313_INACTIVITY_AC] = ADXL313_REG_THRESH_INACT,
|
||||
};
|
||||
|
||||
static const unsigned int adxl313_act_acdc_msk[] = {
|
||||
[ADXL313_ACTIVITY] = ADXL313_REG_ACT_ACDC_MSK,
|
||||
[ADXL313_INACTIVITY] = ADXL313_REG_INACT_ACDC_MSK,
|
||||
[ADXL313_ACTIVITY_AC] = ADXL313_REG_ACT_ACDC_MSK,
|
||||
[ADXL313_INACTIVITY_AC] = ADXL313_REG_INACT_ACDC_MSK,
|
||||
};
|
||||
|
||||
static const struct regmap_range adxl312_readable_reg_range[] = {
|
||||
regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_DEVID0),
|
||||
regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
|
||||
|
@ -46,6 +97,30 @@ const struct regmap_access_table adxl314_readable_regs_table = {
|
|||
};
|
||||
EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, "IIO_ADXL313");
|
||||
|
||||
bool adxl313_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ADXL313_REG_DATA_AXIS(0):
|
||||
case ADXL313_REG_DATA_AXIS(1):
|
||||
case ADXL313_REG_DATA_AXIS(2):
|
||||
case ADXL313_REG_DATA_AXIS(3):
|
||||
case ADXL313_REG_DATA_AXIS(4):
|
||||
case ADXL313_REG_DATA_AXIS(5):
|
||||
case ADXL313_REG_FIFO_STATUS:
|
||||
case ADXL313_REG_INT_SOURCE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adxl313_is_volatile_reg, "IIO_ADXL313");
|
||||
|
||||
static int adxl313_set_measure_en(struct adxl313_data *data, bool en)
|
||||
{
|
||||
return regmap_assign_bits(data->regmap, ADXL313_REG_POWER_CTL,
|
||||
ADXL313_POWER_CTL_MSK, en);
|
||||
}
|
||||
|
||||
static int adxl312_check_id(struct device *dev,
|
||||
struct adxl313_data *data)
|
||||
{
|
||||
|
@ -171,9 +246,10 @@ static const int adxl313_odr_freqs[][2] = {
|
|||
[9] = { 3200, 0 },
|
||||
};
|
||||
|
||||
#define ADXL313_ACCEL_CHANNEL(index, axis) { \
|
||||
#define ADXL313_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = index, \
|
||||
.scan_index = (index), \
|
||||
.address = (reg), \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
|
@ -183,14 +259,77 @@ static const int adxl313_odr_freqs[][2] = {
|
|||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 13, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_event_spec adxl313_activity_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_MAG,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
|
||||
},
|
||||
{
|
||||
/* activity, AC bit set */
|
||||
.type = IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec adxl313_inactivity_events[] = {
|
||||
{
|
||||
/* inactivity */
|
||||
.type = IIO_EV_TYPE_MAG,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
{
|
||||
/* inactivity, AC bit set */
|
||||
.type = IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_PERIOD),
|
||||
},
|
||||
};
|
||||
|
||||
enum adxl313_chans {
|
||||
chan_x, chan_y, chan_z,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adxl313_channels[] = {
|
||||
ADXL313_ACCEL_CHANNEL(0, X),
|
||||
ADXL313_ACCEL_CHANNEL(1, Y),
|
||||
ADXL313_ACCEL_CHANNEL(2, Z),
|
||||
ADXL313_ACCEL_CHANNEL(0, chan_x, X),
|
||||
ADXL313_ACCEL_CHANNEL(1, chan_y, Y),
|
||||
ADXL313_ACCEL_CHANNEL(2, chan_z, Z),
|
||||
{
|
||||
.type = IIO_ACCEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_X_OR_Y_OR_Z,
|
||||
.scan_index = -1, /* Fake channel for axis OR'ing */
|
||||
.event_spec = adxl313_activity_events,
|
||||
.num_event_specs = ARRAY_SIZE(adxl313_activity_events),
|
||||
},
|
||||
{
|
||||
.type = IIO_ACCEL,
|
||||
.modified = 1,
|
||||
.channel2 = IIO_MOD_X_AND_Y_AND_Z,
|
||||
.scan_index = -1, /* Fake channel for axis AND'ing */
|
||||
.event_spec = adxl313_inactivity_events,
|
||||
.num_event_specs = ARRAY_SIZE(adxl313_inactivity_events),
|
||||
},
|
||||
};
|
||||
|
||||
static const unsigned long adxl313_scan_masks[] = {
|
||||
BIT(chan_x) | BIT(chan_y) | BIT(chan_z),
|
||||
0
|
||||
};
|
||||
|
||||
static int adxl313_set_odr(struct adxl313_data *data,
|
||||
|
@ -248,6 +387,230 @@ static int adxl313_read_freq_avail(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int adxl313_set_inact_time_s(struct adxl313_data *data,
|
||||
unsigned int val_s)
|
||||
{
|
||||
unsigned int max_boundary = U8_MAX; /* by register size */
|
||||
unsigned int val = min(val_s, max_boundary);
|
||||
|
||||
return regmap_write(data->regmap, ADXL313_REG_TIME_INACT, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl313_is_act_inact_ac() - Check if AC coupling is enabled.
|
||||
* @data: The device data.
|
||||
* @type: The activity or inactivity type.
|
||||
*
|
||||
* Provide a type of activity or inactivity, combined with either AC coupling
|
||||
* set, or default to DC coupling. This function verifies if the combination is
|
||||
* currently enabled or not.
|
||||
*
|
||||
* Return: if the provided activity type has AC coupling enabled or a negative
|
||||
* error value.
|
||||
*/
|
||||
static int adxl313_is_act_inact_ac(struct adxl313_data *data,
|
||||
enum adxl313_activity_type type)
|
||||
{
|
||||
unsigned int regval;
|
||||
bool coupling;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_ACT_INACT_CTL, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
coupling = adxl313_act_acdc_msk[type] & regval;
|
||||
|
||||
switch (type) {
|
||||
case ADXL313_ACTIVITY:
|
||||
case ADXL313_INACTIVITY:
|
||||
return coupling == ADXL313_COUPLING_DC;
|
||||
case ADXL313_ACTIVITY_AC:
|
||||
case ADXL313_INACTIVITY_AC:
|
||||
return coupling == ADXL313_COUPLING_AC;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_set_act_inact_ac(struct adxl313_data *data,
|
||||
enum adxl313_activity_type type,
|
||||
bool cmd_en)
|
||||
{
|
||||
unsigned int act_inact_ac;
|
||||
|
||||
switch (type) {
|
||||
case ADXL313_ACTIVITY_AC:
|
||||
case ADXL313_INACTIVITY_AC:
|
||||
act_inact_ac = ADXL313_COUPLING_AC && cmd_en;
|
||||
break;
|
||||
case ADXL313_ACTIVITY:
|
||||
case ADXL313_INACTIVITY:
|
||||
act_inact_ac = ADXL313_COUPLING_DC && cmd_en;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_assign_bits(data->regmap, ADXL313_REG_ACT_INACT_CTL,
|
||||
adxl313_act_acdc_msk[type], act_inact_ac);
|
||||
}
|
||||
|
||||
static int adxl313_is_act_inact_en(struct adxl313_data *data,
|
||||
enum adxl313_activity_type type)
|
||||
{
|
||||
unsigned int axis_ctrl;
|
||||
unsigned int regval;
|
||||
bool int_en;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_ACT_INACT_CTL, &axis_ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Check if axis for activity are enabled */
|
||||
switch (type) {
|
||||
case ADXL313_ACTIVITY:
|
||||
case ADXL313_ACTIVITY_AC:
|
||||
if (!FIELD_GET(ADXL313_ACT_XYZ_EN, axis_ctrl))
|
||||
return false;
|
||||
break;
|
||||
case ADXL313_INACTIVITY:
|
||||
case ADXL313_INACTIVITY_AC:
|
||||
if (!FIELD_GET(ADXL313_INACT_XYZ_EN, axis_ctrl))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if specific interrupt is enabled */
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_INT_ENABLE, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
int_en = adxl313_act_int_reg[type] & regval;
|
||||
if (!int_en)
|
||||
return false;
|
||||
|
||||
/* Check if configured coupling matches provided type */
|
||||
return adxl313_is_act_inact_ac(data, type);
|
||||
}
|
||||
|
||||
static int adxl313_set_act_inact_linkbit(struct adxl313_data *data, bool en)
|
||||
{
|
||||
int act_ac_en, inact_ac_en;
|
||||
int act_en, inact_en;
|
||||
|
||||
act_en = adxl313_is_act_inact_en(data, ADXL313_ACTIVITY);
|
||||
if (act_en < 0)
|
||||
return act_en;
|
||||
|
||||
act_ac_en = adxl313_is_act_inact_en(data, ADXL313_ACTIVITY_AC);
|
||||
if (act_ac_en < 0)
|
||||
return act_ac_en;
|
||||
|
||||
inact_en = adxl313_is_act_inact_en(data, ADXL313_INACTIVITY);
|
||||
if (inact_en < 0)
|
||||
return inact_en;
|
||||
|
||||
inact_ac_en = adxl313_is_act_inact_en(data, ADXL313_INACTIVITY_AC);
|
||||
if (inact_ac_en < 0)
|
||||
return inact_ac_en;
|
||||
|
||||
act_en = act_en || act_ac_en;
|
||||
|
||||
inact_en = inact_en || inact_ac_en;
|
||||
|
||||
return regmap_assign_bits(data->regmap, ADXL313_REG_POWER_CTL,
|
||||
ADXL313_POWER_CTL_AUTO_SLEEP | ADXL313_POWER_CTL_LINK,
|
||||
en && act_en && inact_en);
|
||||
}
|
||||
|
||||
static int adxl313_set_act_inact_en(struct adxl313_data *data,
|
||||
enum adxl313_activity_type type,
|
||||
bool cmd_en)
|
||||
{
|
||||
unsigned int axis_ctrl;
|
||||
unsigned int threshold;
|
||||
unsigned int inact_time_s;
|
||||
int ret;
|
||||
|
||||
if (cmd_en) {
|
||||
/* When turning on, check if threshold is valid */
|
||||
ret = regmap_read(data->regmap, adxl313_act_thresh_reg[type],
|
||||
&threshold);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!threshold) /* Just ignore the command if threshold is 0 */
|
||||
return 0;
|
||||
|
||||
/* When turning on inactivity, check if inact time is valid */
|
||||
if (type == ADXL313_INACTIVITY || type == ADXL313_INACTIVITY_AC) {
|
||||
ret = regmap_read(data->regmap,
|
||||
ADXL313_REG_TIME_INACT,
|
||||
&inact_time_s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!inact_time_s)
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* When turning off an activity, ensure that the correct
|
||||
* coupling event is specified. This step helps prevent misuse -
|
||||
* for example, if an AC-coupled activity is active and the
|
||||
* current call attempts to turn off a DC-coupled activity, this
|
||||
* inconsistency should be detected here.
|
||||
*/
|
||||
if (adxl313_is_act_inact_ac(data, type) <= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start modifying configuration registers */
|
||||
ret = adxl313_set_measure_en(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable axis according to the command */
|
||||
switch (type) {
|
||||
case ADXL313_ACTIVITY:
|
||||
case ADXL313_ACTIVITY_AC:
|
||||
axis_ctrl = ADXL313_ACT_XYZ_EN;
|
||||
break;
|
||||
case ADXL313_INACTIVITY:
|
||||
case ADXL313_INACTIVITY_AC:
|
||||
axis_ctrl = ADXL313_INACT_XYZ_EN;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = regmap_assign_bits(data->regmap, ADXL313_REG_ACT_INACT_CTL,
|
||||
axis_ctrl, cmd_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update AC/DC-coupling according to the command */
|
||||
ret = adxl313_set_act_inact_ac(data, type, cmd_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable the interrupt line, according to the command */
|
||||
ret = regmap_assign_bits(data->regmap, ADXL313_REG_INT_ENABLE,
|
||||
adxl313_act_int_reg[type], cmd_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set link-bit and auto-sleep only when ACT and INACT are enabled */
|
||||
ret = adxl313_set_act_inact_linkbit(data, cmd_en);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return adxl313_set_measure_en(data, true);
|
||||
}
|
||||
|
||||
static int adxl313_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
|
@ -321,10 +684,474 @@ static int adxl313_write_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int adxl313_read_mag_config(struct adxl313_data *data,
|
||||
enum iio_event_direction dir,
|
||||
enum adxl313_activity_type type_act,
|
||||
enum adxl313_activity_type type_inact)
|
||||
{
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return !!adxl313_is_act_inact_en(data, type_act);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return !!adxl313_is_act_inact_en(data, type_inact);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_write_mag_config(struct adxl313_data *data,
|
||||
enum iio_event_direction dir,
|
||||
enum adxl313_activity_type type_act,
|
||||
enum adxl313_activity_type type_inact,
|
||||
bool state)
|
||||
{
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return adxl313_set_act_inact_en(data, type_act, state);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return adxl313_set_act_inact_en(data, type_inact, state);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_read_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG:
|
||||
return adxl313_read_mag_config(data, dir,
|
||||
ADXL313_ACTIVITY,
|
||||
ADXL313_INACTIVITY);
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
return adxl313_read_mag_config(data, dir,
|
||||
ADXL313_ACTIVITY_AC,
|
||||
ADXL313_INACTIVITY_AC);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_write_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
bool state)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG:
|
||||
return adxl313_write_mag_config(data, dir,
|
||||
ADXL313_ACTIVITY,
|
||||
ADXL313_INACTIVITY,
|
||||
state);
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
return adxl313_write_mag_config(data, dir,
|
||||
ADXL313_ACTIVITY_AC,
|
||||
ADXL313_INACTIVITY_AC,
|
||||
state);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_read_mag_value(struct adxl313_data *data,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
enum adxl313_activity_type type_act,
|
||||
enum adxl313_activity_type type_inact,
|
||||
int *val, int *val2)
|
||||
{
|
||||
unsigned int threshold;
|
||||
unsigned int period;
|
||||
int ret;
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
ret = regmap_read(data->regmap,
|
||||
adxl313_act_thresh_reg[type_act],
|
||||
&threshold);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = threshold * 15625;
|
||||
*val2 = MICRO;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_EV_DIR_FALLING:
|
||||
ret = regmap_read(data->regmap,
|
||||
adxl313_act_thresh_reg[type_inact],
|
||||
&threshold);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = threshold * 15625;
|
||||
*val2 = MICRO;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_TIME_INACT,
|
||||
&period);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = period;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_write_mag_value(struct adxl313_data *data,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
enum adxl313_activity_type type_act,
|
||||
enum adxl313_activity_type type_inact,
|
||||
int val, int val2)
|
||||
{
|
||||
unsigned int regval;
|
||||
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
/* Scale factor 15.625 mg/LSB */
|
||||
regval = DIV_ROUND_CLOSEST(MICRO * val + val2, 15625);
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
return regmap_write(data->regmap,
|
||||
adxl313_act_thresh_reg[type_act],
|
||||
regval);
|
||||
case IIO_EV_DIR_FALLING:
|
||||
return regmap_write(data->regmap,
|
||||
adxl313_act_thresh_reg[type_inact],
|
||||
regval);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_EV_INFO_PERIOD:
|
||||
return adxl313_set_inact_time_s(data, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_read_event_value(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
int *val, int *val2)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG:
|
||||
return adxl313_read_mag_value(data, dir, info,
|
||||
ADXL313_ACTIVITY,
|
||||
ADXL313_INACTIVITY,
|
||||
val, val2);
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
return adxl313_read_mag_value(data, dir, info,
|
||||
ADXL313_ACTIVITY_AC,
|
||||
ADXL313_INACTIVITY_AC,
|
||||
val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_write_event_value(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info,
|
||||
int val, int val2)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG:
|
||||
return adxl313_write_mag_value(data, dir, info,
|
||||
ADXL313_ACTIVITY,
|
||||
ADXL313_INACTIVITY,
|
||||
val, val2);
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
return adxl313_write_mag_value(data, dir, info,
|
||||
ADXL313_ACTIVITY_AC,
|
||||
ADXL313_INACTIVITY_AC,
|
||||
val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int adxl313_set_watermark(struct iio_dev *indio_dev, unsigned int value)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
value = min(value, ADXL313_FIFO_SIZE - 1);
|
||||
|
||||
ret = adxl313_set_measure_en(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, ADXL313_REG_FIFO_CTL,
|
||||
ADXL313_REG_FIFO_CTL_MODE_MSK, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->watermark = value;
|
||||
|
||||
ret = regmap_set_bits(data->regmap, ADXL313_REG_INT_ENABLE,
|
||||
ADXL313_INT_WATERMARK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return adxl313_set_measure_en(data, true);
|
||||
}
|
||||
|
||||
static int adxl313_get_samples(struct adxl313_data *data)
|
||||
{
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_FIFO_STATUS, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(ADXL313_REG_FIFO_STATUS_ENTRIES_MSK, regval);
|
||||
}
|
||||
|
||||
static int adxl313_fifo_transfer(struct adxl313_data *data, int samples)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
ret = regmap_bulk_read(data->regmap, ADXL313_REG_XYZ_BASE,
|
||||
data->fifo_buf + (i * ADXL313_NUM_AXIS),
|
||||
sizeof(data->fifo_buf[0]) * ADXL313_NUM_AXIS);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl313_fifo_reset() - Reset the FIFO and interrupt status registers.
|
||||
* @data: The device data.
|
||||
*
|
||||
* Reset the FIFO status registers. Reading out status registers clears the
|
||||
* FIFO and interrupt configuration. Thus do not evaluate regmap return values.
|
||||
* Ignore particular read register content. Register content is not processed
|
||||
* any further. Therefore the function returns void.
|
||||
*/
|
||||
static void adxl313_fifo_reset(struct adxl313_data *data)
|
||||
{
|
||||
unsigned int regval;
|
||||
int samples;
|
||||
|
||||
adxl313_set_measure_en(data, false);
|
||||
|
||||
samples = adxl313_get_samples(data);
|
||||
if (samples > 0)
|
||||
adxl313_fifo_transfer(data, samples);
|
||||
|
||||
regmap_read(data->regmap, ADXL313_REG_INT_SOURCE, ®val);
|
||||
|
||||
adxl313_set_measure_en(data, true);
|
||||
}
|
||||
|
||||
static int adxl313_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* Set FIFO modes with measurement turned off, according to datasheet */
|
||||
ret = adxl313_set_measure_en(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
|
||||
FIELD_PREP(ADXL313_REG_FIFO_CTL_SAMPLES_MSK, data->watermark) |
|
||||
FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_STREAM));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return adxl313_set_measure_en(data, true);
|
||||
}
|
||||
|
||||
static int adxl313_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = adxl313_set_measure_en(data, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
|
||||
FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_BYPASS));
|
||||
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return adxl313_set_measure_en(data, true);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops adxl313_buffer_ops = {
|
||||
.postenable = adxl313_buffer_postenable,
|
||||
.predisable = adxl313_buffer_predisable,
|
||||
};
|
||||
|
||||
static int adxl313_fifo_push(struct iio_dev *indio_dev, int samples)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
ret = adxl313_fifo_transfer(data, samples);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ADXL313_NUM_AXIS * samples; i += ADXL313_NUM_AXIS)
|
||||
iio_push_to_buffers(indio_dev, &data->fifo_buf[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adxl313_push_events(struct iio_dev *indio_dev, int int_stat)
|
||||
{
|
||||
s64 ts = iio_get_time_ns(indio_dev);
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
unsigned int regval;
|
||||
int ret = -ENOENT;
|
||||
|
||||
if (FIELD_GET(ADXL313_INT_ACTIVITY, int_stat)) {
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_ACT_INACT_CTL, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (FIELD_GET(ADXL313_REG_ACT_ACDC_MSK, regval)) {
|
||||
/* AC coupled */
|
||||
ret = iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
|
||||
IIO_MOD_X_OR_Y_OR_Z,
|
||||
IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
IIO_EV_DIR_RISING),
|
||||
ts);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* DC coupled, relying on THRESH */
|
||||
ret = iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
|
||||
IIO_MOD_X_OR_Y_OR_Z,
|
||||
IIO_EV_TYPE_MAG,
|
||||
IIO_EV_DIR_RISING),
|
||||
ts);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (FIELD_GET(ADXL313_INT_INACTIVITY, int_stat)) {
|
||||
ret = regmap_read(data->regmap, ADXL313_REG_ACT_INACT_CTL, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (FIELD_GET(ADXL313_REG_INACT_ACDC_MSK, regval)) {
|
||||
/* AC coupled */
|
||||
ret = iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
|
||||
IIO_MOD_X_AND_Y_AND_Z,
|
||||
IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
IIO_EV_DIR_FALLING),
|
||||
ts);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* DC coupled, relying on THRESH */
|
||||
ret = iio_push_event(indio_dev,
|
||||
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
|
||||
IIO_MOD_X_AND_Y_AND_Z,
|
||||
IIO_EV_TYPE_MAG,
|
||||
IIO_EV_DIR_FALLING),
|
||||
ts);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t adxl313_irq_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_dev *indio_dev = p;
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
int samples, int_stat;
|
||||
|
||||
if (regmap_read(data->regmap, ADXL313_REG_INT_SOURCE, &int_stat))
|
||||
return IRQ_NONE;
|
||||
|
||||
/*
|
||||
* In cases of sensor events not handled (still not implemented) by
|
||||
* this driver, the FIFO needs to be drained to become operational
|
||||
* again. In general the sensor configuration only should issue events
|
||||
* which were configured by this driver. Anyway a miss-configuration
|
||||
* easily might end up in a hanging sensor FIFO.
|
||||
*/
|
||||
if (adxl313_push_events(indio_dev, int_stat))
|
||||
goto err_reset_fifo;
|
||||
|
||||
if (FIELD_GET(ADXL313_INT_WATERMARK, int_stat)) {
|
||||
samples = adxl313_get_samples(data);
|
||||
if (samples < 0)
|
||||
goto err_reset_fifo;
|
||||
|
||||
if (adxl313_fifo_push(indio_dev, samples))
|
||||
goto err_reset_fifo;
|
||||
}
|
||||
|
||||
if (FIELD_GET(ADXL313_INT_OVERRUN, int_stat))
|
||||
goto err_reset_fifo;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
err_reset_fifo:
|
||||
adxl313_fifo_reset(data);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adxl313_reg_access(struct iio_dev *indio_dev, unsigned int reg,
|
||||
unsigned int writeval, unsigned int *readval)
|
||||
{
|
||||
struct adxl313_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (readval)
|
||||
return regmap_read(data->regmap, reg, readval);
|
||||
return regmap_write(data->regmap, reg, writeval);
|
||||
}
|
||||
|
||||
static const struct iio_info adxl313_info = {
|
||||
.read_raw = adxl313_read_raw,
|
||||
.write_raw = adxl313_write_raw,
|
||||
.read_event_config = adxl313_read_event_config,
|
||||
.write_event_config = adxl313_write_event_config,
|
||||
.read_event_value = adxl313_read_event_value,
|
||||
.write_event_value = adxl313_write_event_value,
|
||||
.read_avail = adxl313_read_freq_avail,
|
||||
.hwfifo_set_watermark = adxl313_set_watermark,
|
||||
.debugfs_reg_access = &adxl313_reg_access,
|
||||
};
|
||||
|
||||
static int adxl313_setup(struct device *dev, struct adxl313_data *data,
|
||||
|
@ -369,9 +1196,20 @@ static int adxl313_setup(struct device *dev, struct adxl313_data *data,
|
|||
}
|
||||
|
||||
/* Enables measurement mode */
|
||||
return regmap_update_bits(data->regmap, ADXL313_REG_POWER_CTL,
|
||||
ADXL313_POWER_CTL_MSK,
|
||||
ADXL313_MEASUREMENT_MODE);
|
||||
return adxl313_set_measure_en(data, true);
|
||||
}
|
||||
|
||||
static unsigned int adxl313_get_int_type(struct device *dev, int *irq)
|
||||
{
|
||||
*irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
|
||||
if (*irq > 0)
|
||||
return ADXL313_INT1;
|
||||
|
||||
*irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
|
||||
if (*irq > 0)
|
||||
return ADXL313_INT2;
|
||||
|
||||
return ADXL313_INT_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -391,7 +1229,9 @@ int adxl313_core_probe(struct device *dev,
|
|||
{
|
||||
struct adxl313_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
u8 int_line;
|
||||
u8 int_map_msk;
|
||||
int irq, ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -408,6 +1248,7 @@ int adxl313_core_probe(struct device *dev,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = adxl313_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adxl313_channels);
|
||||
indio_dev->available_scan_masks = adxl313_scan_masks;
|
||||
|
||||
ret = adxl313_setup(dev, data, setup);
|
||||
if (ret) {
|
||||
|
@ -415,6 +1256,70 @@ int adxl313_core_probe(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int_line = adxl313_get_int_type(dev, &irq);
|
||||
if (int_line == ADXL313_INT_NONE) {
|
||||
/*
|
||||
* FIFO_BYPASSED mode
|
||||
*
|
||||
* When no interrupt lines are specified, the driver falls back
|
||||
* to use the sensor in FIFO_BYPASS mode. This means turning off
|
||||
* internal FIFO and interrupt generation (since there is no
|
||||
* line specified). Unmaskable interrupts such as overrun or
|
||||
* data ready won't interfere. Even that a FIFO_STREAM mode w/o
|
||||
* connected interrupt line might allow for obtaining raw
|
||||
* measurements, a fallback to disable interrupts when no
|
||||
* interrupt lines are connected seems to be the cleaner
|
||||
* solution.
|
||||
*/
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL,
|
||||
FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK,
|
||||
ADXL313_FIFO_BYPASS));
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* FIFO_STREAM mode */
|
||||
int_map_msk = ADXL313_INT_DREADY | ADXL313_INT_ACTIVITY |
|
||||
ADXL313_INT_INACTIVITY | ADXL313_INT_WATERMARK |
|
||||
ADXL313_INT_OVERRUN;
|
||||
ret = regmap_assign_bits(data->regmap, ADXL313_REG_INT_MAP,
|
||||
int_map_msk, int_line == ADXL313_INT2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Reset or configure the registers with reasonable default
|
||||
* values. As having 0 in most cases may result in undesirable
|
||||
* behavior if the interrupts are enabled.
|
||||
*/
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_ACT_INACT_CTL, 0x00);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_TIME_INACT, 5);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_THRESH_INACT, 0x4f);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap, ADXL313_REG_THRESH_ACT, 0x52);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
|
||||
&adxl313_buffer_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
&adxl313_irq_handler,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
indio_dev->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, "IIO_ADXL313");
|
||||
|
|
|
@ -21,6 +21,8 @@ static const struct regmap_config adxl31x_i2c_regmap_config[] = {
|
|||
.rd_table = &adxl312_readable_regs_table,
|
||||
.wr_table = &adxl312_writable_regs_table,
|
||||
.max_register = 0x39,
|
||||
.volatile_reg = adxl313_is_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
},
|
||||
[ADXL313] = {
|
||||
.reg_bits = 8,
|
||||
|
@ -28,6 +30,8 @@ static const struct regmap_config adxl31x_i2c_regmap_config[] = {
|
|||
.rd_table = &adxl313_readable_regs_table,
|
||||
.wr_table = &adxl313_writable_regs_table,
|
||||
.max_register = 0x39,
|
||||
.volatile_reg = adxl313_is_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
},
|
||||
[ADXL314] = {
|
||||
.reg_bits = 8,
|
||||
|
@ -35,6 +39,8 @@ static const struct regmap_config adxl31x_i2c_regmap_config[] = {
|
|||
.rd_table = &adxl314_readable_regs_table,
|
||||
.wr_table = &adxl314_writable_regs_table,
|
||||
.max_register = 0x39,
|
||||
.volatile_reg = adxl313_is_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ static const struct regmap_config adxl31x_spi_regmap_config[] = {
|
|||
.max_register = 0x39,
|
||||
/* Setting bits 7 and 6 enables multiple-byte read */
|
||||
.read_flag_mask = BIT(7) | BIT(6),
|
||||
.volatile_reg = adxl313_is_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
},
|
||||
[ADXL313] = {
|
||||
.reg_bits = 8,
|
||||
|
@ -33,6 +35,8 @@ static const struct regmap_config adxl31x_spi_regmap_config[] = {
|
|||
.max_register = 0x39,
|
||||
/* Setting bits 7 and 6 enables multiple-byte read */
|
||||
.read_flag_mask = BIT(7) | BIT(6),
|
||||
.volatile_reg = adxl313_is_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
},
|
||||
[ADXL314] = {
|
||||
.reg_bits = 8,
|
||||
|
@ -42,6 +46,8 @@ static const struct regmap_config adxl31x_spi_regmap_config[] = {
|
|||
.max_register = 0x39,
|
||||
/* Setting bits 7 and 6 enables multiple-byte read */
|
||||
.read_flag_mask = BIT(7) | BIT(6),
|
||||
.volatile_reg = adxl313_is_volatile_reg,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -69,11 +69,10 @@
|
|||
* BW_RATE bits - Bandwidth and output data rate. The default value is
|
||||
* 0x0A, which translates to a 100 Hz output data rate
|
||||
*/
|
||||
#define ADXL345_BW_RATE GENMASK(3, 0)
|
||||
#define ADXL345_BW_RATE_MSK GENMASK(3, 0)
|
||||
#define ADXL345_BW_LOW_POWER BIT(4)
|
||||
#define ADXL345_BASE_RATE_NANO_HZ 97656250LL
|
||||
|
||||
#define ADXL345_POWER_CTL_STANDBY 0x00
|
||||
#define ADXL345_POWER_CTL_WAKEUP GENMASK(1, 0)
|
||||
#define ADXL345_POWER_CTL_SLEEP BIT(2)
|
||||
#define ADXL345_POWER_CTL_MEASURE BIT(3)
|
||||
|
|
|
@ -64,11 +64,75 @@ static const unsigned int adxl345_tap_time_reg[] = {
|
|||
[ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR,
|
||||
};
|
||||
|
||||
enum adxl345_odr {
|
||||
ADXL345_ODR_0P10HZ = 0,
|
||||
ADXL345_ODR_0P20HZ,
|
||||
ADXL345_ODR_0P39HZ,
|
||||
ADXL345_ODR_0P78HZ,
|
||||
ADXL345_ODR_1P56HZ,
|
||||
ADXL345_ODR_3P13HZ,
|
||||
ADXL345_ODR_6P25HZ,
|
||||
ADXL345_ODR_12P50HZ,
|
||||
ADXL345_ODR_25HZ,
|
||||
ADXL345_ODR_50HZ,
|
||||
ADXL345_ODR_100HZ,
|
||||
ADXL345_ODR_200HZ,
|
||||
ADXL345_ODR_400HZ,
|
||||
ADXL345_ODR_800HZ,
|
||||
ADXL345_ODR_1600HZ,
|
||||
ADXL345_ODR_3200HZ,
|
||||
};
|
||||
|
||||
enum adxl345_range {
|
||||
ADXL345_2G_RANGE = 0,
|
||||
ADXL345_4G_RANGE,
|
||||
ADXL345_8G_RANGE,
|
||||
ADXL345_16G_RANGE,
|
||||
};
|
||||
|
||||
/* Certain features recommend 12.5 Hz - 400 Hz ODR */
|
||||
static const int adxl345_odr_tbl[][2] = {
|
||||
[ADXL345_ODR_0P10HZ] = { 0, 97000 },
|
||||
[ADXL345_ODR_0P20HZ] = { 0, 195000 },
|
||||
[ADXL345_ODR_0P39HZ] = { 0, 390000 },
|
||||
[ADXL345_ODR_0P78HZ] = { 0, 781000 },
|
||||
[ADXL345_ODR_1P56HZ] = { 1, 562000 },
|
||||
[ADXL345_ODR_3P13HZ] = { 3, 125000 },
|
||||
[ADXL345_ODR_6P25HZ] = { 6, 250000 },
|
||||
[ADXL345_ODR_12P50HZ] = { 12, 500000 },
|
||||
[ADXL345_ODR_25HZ] = { 25, 0 },
|
||||
[ADXL345_ODR_50HZ] = { 50, 0 },
|
||||
[ADXL345_ODR_100HZ] = { 100, 0 },
|
||||
[ADXL345_ODR_200HZ] = { 200, 0 },
|
||||
[ADXL345_ODR_400HZ] = { 400, 0 },
|
||||
[ADXL345_ODR_800HZ] = { 800, 0 },
|
||||
[ADXL345_ODR_1600HZ] = { 1600, 0 },
|
||||
[ADXL345_ODR_3200HZ] = { 3200, 0 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Full resolution frequency table:
|
||||
* (g * 2 * 9.80665) / (2^(resolution) - 1)
|
||||
*
|
||||
* resolution := 13 (full)
|
||||
* g := 2|4|8|16
|
||||
*
|
||||
* 2g at 13bit: 0.004789
|
||||
* 4g at 13bit: 0.009578
|
||||
* 8g at 13bit: 0.019156
|
||||
* 16g at 16bit: 0.038312
|
||||
*/
|
||||
static const int adxl345_fullres_range_tbl[][2] = {
|
||||
[ADXL345_2G_RANGE] = { 0, 4789 },
|
||||
[ADXL345_4G_RANGE] = { 0, 9578 },
|
||||
[ADXL345_8G_RANGE] = { 0, 19156 },
|
||||
[ADXL345_16G_RANGE] = { 0, 38312 },
|
||||
};
|
||||
|
||||
struct adxl345_state {
|
||||
const struct adxl345_chip_info *info;
|
||||
struct regmap *regmap;
|
||||
bool fifo_delay; /* delay: delay is needed for SPI */
|
||||
int irq;
|
||||
u8 watermark;
|
||||
u8 fifo_mode;
|
||||
|
||||
|
@ -79,7 +143,7 @@ struct adxl345_state {
|
|||
__le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
static struct iio_event_spec adxl345_events[] = {
|
||||
static const struct iio_event_spec adxl345_events[] = {
|
||||
{
|
||||
/* single tap */
|
||||
.type = IIO_EV_TYPE_GESTURE,
|
||||
|
@ -107,6 +171,8 @@ static struct iio_event_spec adxl345_events[] = {
|
|||
BIT(IIO_CHAN_INFO_CALIBBIAS), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = (index), \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
|
@ -167,9 +233,8 @@ EXPORT_SYMBOL_NS_GPL(adxl345_is_volatile_reg, "IIO_ADXL345");
|
|||
*/
|
||||
static int adxl345_set_measure_en(struct adxl345_state *st, bool en)
|
||||
{
|
||||
unsigned int val = en ? ADXL345_POWER_CTL_MEASURE : ADXL345_POWER_CTL_STANDBY;
|
||||
|
||||
return regmap_write(st->regmap, ADXL345_REG_POWER_CTL, val);
|
||||
return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL,
|
||||
ADXL345_POWER_CTL_MEASURE, en);
|
||||
}
|
||||
|
||||
/* tap */
|
||||
|
@ -383,14 +448,82 @@ static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int,
|
|||
return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us);
|
||||
}
|
||||
|
||||
static int adxl345_find_odr(struct adxl345_state *st, int val,
|
||||
int val2, enum adxl345_odr *odr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adxl345_odr_tbl); i++) {
|
||||
if (val == adxl345_odr_tbl[i][0] &&
|
||||
val2 == adxl345_odr_tbl[i][1]) {
|
||||
*odr = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr)
|
||||
{
|
||||
return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
|
||||
ADXL345_BW_RATE_MSK,
|
||||
FIELD_PREP(ADXL345_BW_RATE_MSK, odr));
|
||||
}
|
||||
|
||||
static int adxl345_find_range(struct adxl345_state *st, int val, int val2,
|
||||
enum adxl345_range *range)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adxl345_fullres_range_tbl); i++) {
|
||||
if (val == adxl345_fullres_range_tbl[i][0] &&
|
||||
val2 == adxl345_fullres_range_tbl[i][1]) {
|
||||
*range = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range)
|
||||
{
|
||||
return regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
|
||||
ADXL345_DATA_FORMAT_RANGE,
|
||||
FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range));
|
||||
}
|
||||
|
||||
static int adxl345_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type,
|
||||
int *length, long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*vals = (int *)adxl345_fullres_range_tbl;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
*length = ARRAY_SIZE(adxl345_fullres_range_tbl) * 2;
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*vals = (int *)adxl345_odr_tbl;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
*length = ARRAY_SIZE(adxl345_odr_tbl) * 2;
|
||||
return IIO_AVAIL_LIST;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adxl345_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
__le16 accel;
|
||||
long long samp_freq_nhz;
|
||||
unsigned int regval;
|
||||
enum adxl345_odr odr;
|
||||
enum adxl345_range range;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
|
@ -409,8 +542,12 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
*val = sign_extend32(le16_to_cpu(accel), 12);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = st->info->uscale;
|
||||
ret = regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
range = FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval);
|
||||
*val = adxl345_fullres_range_tbl[range][0];
|
||||
*val2 = adxl345_fullres_range_tbl[range][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = regmap_read(st->regmap,
|
||||
|
@ -428,12 +565,10 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
|
|||
ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
|
||||
(regval & ADXL345_BW_RATE);
|
||||
*val = div_s64_rem(samp_freq_nhz, NANOHZ_PER_HZ, val2);
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
|
||||
*val = adxl345_odr_tbl[odr][0];
|
||||
*val2 = adxl345_odr_tbl[odr][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
@ -444,7 +579,13 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
|
|||
int val, int val2, long mask)
|
||||
{
|
||||
struct adxl345_state *st = iio_priv(indio_dev);
|
||||
s64 n;
|
||||
enum adxl345_range range;
|
||||
enum adxl345_odr odr;
|
||||
int ret;
|
||||
|
||||
ret = adxl345_set_measure_en(st, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
|
@ -452,20 +593,35 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
|
|||
* 8-bit resolution at +/- 2g, that is 4x accel data scale
|
||||
* factor
|
||||
*/
|
||||
return regmap_write(st->regmap,
|
||||
ADXL345_REG_OFS_AXIS(chan->address),
|
||||
val / 4);
|
||||
ret = regmap_write(st->regmap,
|
||||
ADXL345_REG_OFS_AXIS(chan->address),
|
||||
val / 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
n = div_s64(val * NANOHZ_PER_HZ + val2,
|
||||
ADXL345_BASE_RATE_NANO_HZ);
|
||||
ret = adxl345_find_odr(st, val, val2, &odr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
|
||||
ADXL345_BW_RATE,
|
||||
clamp_val(ilog2(n), 0,
|
||||
ADXL345_BW_RATE));
|
||||
ret = adxl345_set_odr(st, odr);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = adxl345_find_range(st, val, val2, &range);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adxl345_set_range(st, range);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
return adxl345_set_measure_en(st, true);
|
||||
}
|
||||
|
||||
static int adxl345_read_event_config(struct iio_dev *indio_dev,
|
||||
|
@ -552,15 +708,15 @@ static int adxl345_read_event_value(struct iio_dev *indio_dev,
|
|||
return IIO_VAL_INT;
|
||||
case IIO_EV_INFO_TIMEOUT:
|
||||
*val = st->tap_duration_us;
|
||||
*val2 = 1000000;
|
||||
*val2 = MICRO;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_EV_INFO_RESET_TIMEOUT:
|
||||
*val = st->tap_window_us;
|
||||
*val2 = 1000000;
|
||||
*val2 = MICRO;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case IIO_EV_INFO_TAP2_MIN_DELAY:
|
||||
*val = st->tap_latent_us;
|
||||
*val2 = 1000000;
|
||||
*val2 = MICRO;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -653,8 +809,10 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
|
|||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -667,19 +825,6 @@ static void adxl345_powerdown(void *ptr)
|
|||
adxl345_set_measure_en(st, false);
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
|
||||
"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
|
||||
);
|
||||
|
||||
static struct attribute *adxl345_attrs[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adxl345_attrs_group = {
|
||||
.attrs = adxl345_attrs,
|
||||
};
|
||||
|
||||
static int adxl345_set_fifo(struct adxl345_state *st)
|
||||
{
|
||||
unsigned int intio;
|
||||
|
@ -740,15 +885,12 @@ static int adxl345_get_samples(struct adxl345_state *st)
|
|||
*/
|
||||
static int adxl345_fifo_transfer(struct adxl345_state *st, int samples)
|
||||
{
|
||||
size_t count;
|
||||
int i, ret = 0;
|
||||
|
||||
/* count is the 3x the fifo_buf element size, hence 6B */
|
||||
count = sizeof(st->fifo_buf[0]) * ADXL345_DIRS;
|
||||
for (i = 0; i < samples; i++) {
|
||||
/* read 3x 2 byte elements from base address into next fifo_buf position */
|
||||
ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE,
|
||||
st->fifo_buf + (i * count / 2), count);
|
||||
st->fifo_buf + (i * ADXL345_DIRS),
|
||||
sizeof(st->fifo_buf[0]) * ADXL345_DIRS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -931,9 +1073,9 @@ err:
|
|||
}
|
||||
|
||||
static const struct iio_info adxl345_info = {
|
||||
.attrs = &adxl345_attrs_group,
|
||||
.read_raw = adxl345_read_raw,
|
||||
.write_raw = adxl345_write_raw,
|
||||
.read_avail = adxl345_read_avail,
|
||||
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
|
||||
.read_event_config = adxl345_read_event_config,
|
||||
.write_event_config = adxl345_write_event_config,
|
||||
|
@ -943,6 +1085,19 @@ static const struct iio_info adxl345_info = {
|
|||
.hwfifo_set_watermark = adxl345_set_watermark,
|
||||
};
|
||||
|
||||
static int adxl345_get_int_line(struct device *dev, int *irq)
|
||||
{
|
||||
*irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
|
||||
if (*irq > 0)
|
||||
return ADXL345_INT1;
|
||||
|
||||
*irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
|
||||
if (*irq > 0)
|
||||
return ADXL345_INT2;
|
||||
|
||||
return ADXL345_INT_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* adxl345_core_probe() - Probe and setup for the accelerometer.
|
||||
* @dev: Driver model representation of the device
|
||||
|
@ -973,6 +1128,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
ADXL345_DATA_FORMAT_FULL_RES |
|
||||
ADXL345_DATA_FORMAT_SELF_TEST);
|
||||
unsigned int tap_threshold;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
|
@ -999,6 +1155,19 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
|
||||
indio_dev->available_scan_masks = adxl345_scan_masks;
|
||||
|
||||
/*
|
||||
* Using I2C at 100kHz would limit the maximum ODR to 200Hz, operation
|
||||
* at an output rate above the recommended maximum may result in
|
||||
* undesired behavior.
|
||||
*/
|
||||
ret = adxl345_set_odr(st, ADXL345_ODR_200HZ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adxl345_set_range(st, ADXL345_16G_RANGE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Reset interrupts at start up */
|
||||
ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
|
||||
if (ret)
|
||||
|
@ -1044,23 +1213,16 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
|
||||
if (st->irq < 0) {
|
||||
intio = ADXL345_INT2;
|
||||
st->irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
|
||||
if (st->irq < 0)
|
||||
intio = ADXL345_INT_NONE;
|
||||
}
|
||||
|
||||
intio = adxl345_get_int_line(dev, &irq);
|
||||
if (intio != ADXL345_INT_NONE) {
|
||||
/*
|
||||
* Any bits set to 0 in the INT map register send their respective
|
||||
* interrupts to the INT1 pin, whereas bits set to 1 send their respective
|
||||
* interrupts to the INT2 pin. The intio shall convert this accordingly.
|
||||
* In the INT map register, bits set to 0 route their
|
||||
* corresponding interrupts to the INT1 pin, while bits set to 1
|
||||
* route them to the INT2 pin. The intio should handle this
|
||||
* mapping accordingly.
|
||||
*/
|
||||
regval = intio ? 0xff : 0;
|
||||
|
||||
ret = regmap_write(st->regmap, ADXL345_REG_INT_MAP, regval);
|
||||
ret = regmap_assign_bits(st->regmap, ADXL345_REG_INT_MAP,
|
||||
U8_MAX, intio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1073,7 +1235,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, st->irq, NULL,
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
&adxl345_irq_handler,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
indio_dev->name, indio_dev);
|
||||
|
|
|
@ -600,10 +600,9 @@ static int adxl372_get_status(struct adxl372_state *st,
|
|||
|
||||
static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample)
|
||||
{
|
||||
__be16 axis_sample[3];
|
||||
__be16 axis_sample[3] = { };
|
||||
int i = 0;
|
||||
|
||||
memset(axis_sample, 0, 3 * sizeof(__be16));
|
||||
if (ADXL372_X_AXIS_EN(st->fifo_axis_mask))
|
||||
axis_sample[i++] = sample[0];
|
||||
if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask))
|
||||
|
|
|
@ -29,9 +29,6 @@
|
|||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define BMA180_DRV_NAME "bma180"
|
||||
#define BMA180_IRQ_NAME "bma180_event"
|
||||
|
||||
enum chip_ids {
|
||||
BMA023,
|
||||
BMA150,
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
|
||||
#include "bmc150-accel.h"
|
||||
|
||||
#define BMC150_ACCEL_DRV_NAME "bmc150_accel"
|
||||
#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event"
|
||||
|
||||
#define BMC150_ACCEL_REG_CHIP_ID 0x00
|
||||
|
||||
#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B
|
||||
|
@ -1706,7 +1703,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
bmc150_accel_irq_handler,
|
||||
bmc150_accel_irq_thread_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
BMC150_ACCEL_IRQ_NAME,
|
||||
"bmc150_accel_event",
|
||||
indio_dev);
|
||||
if (ret)
|
||||
goto err_buffer_cleanup;
|
||||
|
|
|
@ -5,27 +5,37 @@
|
|||
* ROHM/KIONIX accelerometer driver
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/time64.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "kionix-kx022a.h"
|
||||
|
||||
/*
|
||||
|
|
|
@ -26,9 +26,6 @@
|
|||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/accel/kxcjk_1013.h>
|
||||
|
||||
#define KXCJK1013_DRV_NAME "kxcjk1013"
|
||||
#define KXCJK1013_IRQ_NAME "kxcjk1013_event"
|
||||
|
||||
#define KXTF9_REG_HP_XOUT_L 0x00
|
||||
#define KXTF9_REG_HP_XOUT_H 0x01
|
||||
#define KXTF9_REG_HP_YOUT_L 0x02
|
||||
|
@ -1464,7 +1461,7 @@ static int kxcjk1013_probe(struct i2c_client *client)
|
|||
kxcjk1013_data_rdy_trig_poll,
|
||||
kxcjk1013_event_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
KXCJK1013_IRQ_NAME,
|
||||
"kxcjk1013_event",
|
||||
indio_dev);
|
||||
if (ret)
|
||||
goto err_poweroff;
|
||||
|
@ -1674,7 +1671,7 @@ MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
|
|||
|
||||
static struct i2c_driver kxcjk1013_driver = {
|
||||
.driver = {
|
||||
.name = KXCJK1013_DRV_NAME,
|
||||
.name = "kxcjk1013",
|
||||
.acpi_match_table = kx_acpi_match,
|
||||
.of_match_table = kxcjk1013_of_match,
|
||||
.pm = pm_ptr(&kxcjk1013_pm_ops),
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include "mma9551_core.h"
|
||||
|
||||
#define MMA9551_DRV_NAME "mma9551"
|
||||
#define MMA9551_IRQ_NAME "mma9551_event"
|
||||
#define MMA9551_GPIO_COUNT 4
|
||||
|
||||
/* Tilt application (inclination in IIO terms). */
|
||||
|
@ -422,7 +420,7 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev)
|
|||
ret = devm_request_threaded_irq(dev, data->irqs[i],
|
||||
NULL, mma9551_event_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
MMA9551_IRQ_NAME, indio_dev);
|
||||
"mma9551_event", indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "request irq %d failed\n", data->irqs[i]);
|
||||
return ret;
|
||||
|
@ -592,7 +590,7 @@ MODULE_DEVICE_TABLE(i2c, mma9551_id);
|
|||
|
||||
static struct i2c_driver mma9551_driver = {
|
||||
.driver = {
|
||||
.name = MMA9551_DRV_NAME,
|
||||
.name = "mma9551",
|
||||
.acpi_match_table = mma9551_acpi_match,
|
||||
.pm = pm_ptr(&mma9551_pm_ops),
|
||||
},
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include "mma9551_core.h"
|
||||
|
||||
#define MMA9553_DRV_NAME "mma9553"
|
||||
#define MMA9553_IRQ_NAME "mma9553_event"
|
||||
|
||||
/* Pedometer configuration registers (R/W) */
|
||||
#define MMA9553_REG_CONF_SLEEPMIN 0x00
|
||||
#define MMA9553_REG_CONF_SLEEPMAX 0x02
|
||||
|
@ -100,7 +97,7 @@ enum activity_level {
|
|||
ACTIVITY_RUNNING,
|
||||
};
|
||||
|
||||
static struct mma9553_event_info {
|
||||
static const struct mma9553_event_info {
|
||||
enum iio_chan_type type;
|
||||
enum iio_modifier mod;
|
||||
enum iio_event_direction dir;
|
||||
|
@ -155,7 +152,7 @@ static struct mma9553_event_info {
|
|||
#define MMA9553_EVENTS_INFO_SIZE ARRAY_SIZE(mma9553_events_info)
|
||||
|
||||
struct mma9553_event {
|
||||
struct mma9553_event_info *info;
|
||||
const struct mma9553_event_info *info;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
|
@ -1102,7 +1099,7 @@ static int mma9553_probe(struct i2c_client *client)
|
|||
mma9553_irq_handler,
|
||||
mma9553_event_handler,
|
||||
IRQF_TRIGGER_RISING,
|
||||
MMA9553_IRQ_NAME, indio_dev);
|
||||
"mma9553_event", indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "request irq %d failed\n",
|
||||
client->irq);
|
||||
|
@ -1230,7 +1227,7 @@ MODULE_DEVICE_TABLE(i2c, mma9553_id);
|
|||
|
||||
static struct i2c_driver mma9553_driver = {
|
||||
.driver = {
|
||||
.name = MMA9553_DRV_NAME,
|
||||
.name = "mma9553",
|
||||
.acpi_match_table = mma9553_acpi_match,
|
||||
.pm = pm_ptr(&mma9553_pm_ops),
|
||||
},
|
||||
|
|
|
@ -897,9 +897,7 @@ static irqreturn_t msa311_buffer_thread(int irq, void *p)
|
|||
struct {
|
||||
__le16 channels[MSA311_SI_Z + 1];
|
||||
aligned_s64 ts;
|
||||
} buf;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
} buf = { };
|
||||
|
||||
mutex_lock(&msa311->lock);
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#define MXC4005_DRV_NAME "mxc4005"
|
||||
#define MXC4005_IRQ_NAME "mxc4005_event"
|
||||
#define MXC4005_REGMAP_NAME "mxc4005_regmap"
|
||||
|
||||
#define MXC4005_REG_XOUT_UPPER 0x03
|
||||
#define MXC4005_REG_XOUT_LOWER 0x04
|
||||
|
@ -138,7 +136,7 @@ static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg)
|
|||
}
|
||||
|
||||
static const struct regmap_config mxc4005_regmap_config = {
|
||||
.name = MXC4005_REGMAP_NAME,
|
||||
.name = "mxc4005_regmap",
|
||||
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
@ -493,7 +491,7 @@ static int mxc4005_probe(struct i2c_client *client)
|
|||
NULL,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT,
|
||||
MXC4005_IRQ_NAME,
|
||||
"mxc4005_event",
|
||||
data->dready_trig);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define MXC6255_DRV_NAME "mxc6255"
|
||||
#define MXC6255_REGMAP_NAME "mxc6255_regmap"
|
||||
|
||||
#define MXC6255_REG_XOUT 0x00
|
||||
#define MXC6255_REG_YOUT 0x01
|
||||
|
@ -105,7 +104,7 @@ static bool mxc6255_is_readable_reg(struct device *dev, unsigned int reg)
|
|||
}
|
||||
|
||||
static const struct regmap_config mxc6255_regmap_config = {
|
||||
.name = MXC6255_REGMAP_NAME,
|
||||
.name = "mxc6255_regmap",
|
||||
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
|
|
@ -369,23 +369,20 @@ static int sca3000_write_ctrl_reg(struct sca3000_state *st,
|
|||
|
||||
ret = sca3000_reg_lock_on(st);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
if (ret) {
|
||||
ret = __sca3000_unlock_reg_lock(st);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the control select register */
|
||||
ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, sel);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
|
||||
/* Write the actual value into the register */
|
||||
ret = sca3000_write_reg(st, SCA3000_REG_CTRL_DATA_ADDR, val);
|
||||
|
||||
error_ret:
|
||||
return ret;
|
||||
return sca3000_write_reg(st, SCA3000_REG_CTRL_DATA_ADDR, val);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -402,22 +399,20 @@ static int sca3000_read_ctrl_reg(struct sca3000_state *st,
|
|||
|
||||
ret = sca3000_reg_lock_on(st);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
if (ret) {
|
||||
ret = __sca3000_unlock_reg_lock(st);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
}
|
||||
/* Set the control select register */
|
||||
ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, ctrl_reg);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
ret = sca3000_read_data_short(st, SCA3000_REG_CTRL_DATA_ADDR, 1);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
return st->rx[0];
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -577,7 +572,8 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st,
|
|||
|
||||
ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
|
||||
switch (SCA3000_REG_MODE_MODE_MASK & st->rx[0]) {
|
||||
case SCA3000_REG_MODE_MEAS_MODE_NORMAL:
|
||||
*base_freq = info->measurement_mode_freq;
|
||||
|
@ -591,7 +587,6 @@ static inline int __sca3000_get_base_freq(struct sca3000_state *st,
|
|||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -834,7 +829,7 @@ static ssize_t sca3000_read_av_freq(struct device *dev,
|
|||
val = st->rx[0];
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
return ret;
|
||||
|
||||
switch (val & SCA3000_REG_MODE_MODE_MASK) {
|
||||
case SCA3000_REG_MODE_MEAS_MODE_NORMAL:
|
||||
|
@ -857,8 +852,6 @@ static ssize_t sca3000_read_av_freq(struct device *dev,
|
|||
break;
|
||||
}
|
||||
return len;
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define SCA3300_ALIAS "sca3300"
|
||||
|
||||
#define SCA3300_CRC8_POLYNOMIAL 0x1d
|
||||
|
||||
/* Device mode register */
|
||||
|
@ -674,7 +672,7 @@ MODULE_DEVICE_TABLE(spi, sca3300_ids);
|
|||
|
||||
static struct spi_driver sca3300_driver = {
|
||||
.driver = {
|
||||
.name = SCA3300_ALIAS,
|
||||
.name = "sca3300",
|
||||
.of_match_table = sca3300_dt_ids,
|
||||
},
|
||||
.probe = sca3300_probe,
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#define STK8312_ALL_CHANNEL_SIZE 3
|
||||
|
||||
#define STK8312_DRIVER_NAME "stk8312"
|
||||
#define STK8312_IRQ_NAME "stk8312_event"
|
||||
|
||||
/*
|
||||
* The accelerometer has two measurement ranges:
|
||||
|
@ -543,7 +542,7 @@ static int stk8312_probe(struct i2c_client *client)
|
|||
NULL,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_ONESHOT,
|
||||
STK8312_IRQ_NAME,
|
||||
"stk8312_event",
|
||||
indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "request irq %d failed\n",
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
#define STK8BA50_ALL_CHANNEL_SIZE 6
|
||||
|
||||
#define STK8BA50_DRIVER_NAME "stk8ba50"
|
||||
#define STK8BA50_IRQ_NAME "stk8ba50_event"
|
||||
|
||||
#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
|
||||
|
||||
|
@ -436,7 +435,7 @@ static int stk8ba50_probe(struct i2c_client *client)
|
|||
NULL,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_ONESHOT,
|
||||
STK8BA50_IRQ_NAME,
|
||||
"stk8ba50_event",
|
||||
indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "request irq %d failed\n",
|
||||
|
|
|
@ -22,7 +22,9 @@ config AB8500_GPADC
|
|||
config AD_SIGMA_DELTA
|
||||
tristate
|
||||
select IIO_BUFFER
|
||||
select IIO_BUFFER_DMAENGINE
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select SPI_OFFLOAD
|
||||
|
||||
config AD4000
|
||||
tristate "Analog Devices AD4000 ADC Driver"
|
||||
|
@ -55,6 +57,20 @@ config AD4030
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4030.
|
||||
|
||||
config AD4080
|
||||
tristate "Analog Devices AD4080 high speed ADC"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
select IIO_BACKEND
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD4080
|
||||
high speed, low noise, low distortion, 20-bit, Easy Drive,
|
||||
successive approximation register (SAR) analog-to-digital
|
||||
converter (ADC). Supports iio_backended devices for AD4080.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4080.
|
||||
|
||||
config AD4130
|
||||
tristate "Analog Device AD4130 ADC Driver"
|
||||
depends on SPI
|
||||
|
@ -70,6 +86,22 @@ config AD4130
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4130.
|
||||
|
||||
|
||||
config AD4170_4
|
||||
tristate "Analog Device AD4170-4 ADC Driver"
|
||||
depends on SPI
|
||||
select REGMAP_SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
depends on COMMON_CLK
|
||||
depends on GPIOLIB
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD4170-4 SPI analog
|
||||
to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad4170-4.
|
||||
|
||||
config AD4695
|
||||
tristate "Analog Device AD4695 ADC Driver"
|
||||
depends on SPI
|
||||
|
@ -252,6 +284,16 @@ config AD7380
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7380.
|
||||
|
||||
config AD7405
|
||||
tristate "Analog Device AD7405 ADC Driver"
|
||||
depends on IIO_BACKEND
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD7405, ADUM7701,
|
||||
ADUM7702, ADUM7703 analog to digital converters (ADC).
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad7405.
|
||||
|
||||
config AD7476
|
||||
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI"
|
||||
depends on SPI
|
||||
|
@ -330,6 +372,7 @@ config AD7766
|
|||
config AD7768_1
|
||||
tristate "Analog Devices AD7768-1 ADC driver"
|
||||
depends on SPI
|
||||
select REGULATOR
|
||||
select REGMAP_SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGER
|
||||
|
|
|
@ -10,7 +10,9 @@ obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
|
|||
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
|
||||
obj-$(CONFIG_AD4000) += ad4000.o
|
||||
obj-$(CONFIG_AD4030) += ad4030.o
|
||||
obj-$(CONFIG_AD4080) += ad4080.o
|
||||
obj-$(CONFIG_AD4130) += ad4130.o
|
||||
obj-$(CONFIG_AD4170_4) += ad4170-4.o
|
||||
obj-$(CONFIG_AD4695) += ad4695.o
|
||||
obj-$(CONFIG_AD4851) += ad4851.o
|
||||
obj-$(CONFIG_AD7091R) += ad7091r-base.o
|
||||
|
@ -26,6 +28,7 @@ obj-$(CONFIG_AD7291) += ad7291.o
|
|||
obj-$(CONFIG_AD7292) += ad7292.o
|
||||
obj-$(CONFIG_AD7298) += ad7298.o
|
||||
obj-$(CONFIG_AD7380) += ad7380.o
|
||||
obj-$(CONFIG_AD7405) += ad7405.o
|
||||
obj-$(CONFIG_AD7476) += ad7476.o
|
||||
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
|
||||
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
|
||||
|
|
|
@ -554,7 +554,7 @@ static void ad4000_fill_scale_tbl(struct ad4000_state *st,
|
|||
val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
|
||||
|
||||
/* Would multiply by NANO here but we multiplied by extra MILLI */
|
||||
tmp2 = shift_right((u64)val * MICRO, scale_bits);
|
||||
tmp2 = (u64)val * MICRO >> scale_bits;
|
||||
tmp0 = div_s64_rem(tmp2, NANO, &tmp1);
|
||||
|
||||
/* Store scale for when span compression is disabled */
|
||||
|
|
619
drivers/iio/adc/ad4080.c
Normal file
619
drivers/iio/adc/ad4080.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Analog Devices AD4080 SPI ADC driver
|
||||
*
|
||||
* Copyright 2025 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iio/backend.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
/* Register Definition */
|
||||
#define AD4080_REG_INTERFACE_CONFIG_A 0x00
|
||||
#define AD4080_REG_INTERFACE_CONFIG_B 0x01
|
||||
#define AD4080_REG_DEVICE_CONFIG 0x02
|
||||
#define AD4080_REG_CHIP_TYPE 0x03
|
||||
#define AD4080_REG_PRODUCT_ID_L 0x04
|
||||
#define AD4080_REG_PRODUCT_ID_H 0x05
|
||||
#define AD4080_REG_CHIP_GRADE 0x06
|
||||
#define AD4080_REG_SCRATCH_PAD 0x0A
|
||||
#define AD4080_REG_SPI_REVISION 0x0B
|
||||
#define AD4080_REG_VENDOR_L 0x0C
|
||||
#define AD4080_REG_VENDOR_H 0x0D
|
||||
#define AD4080_REG_STREAM_MODE 0x0E
|
||||
#define AD4080_REG_TRANSFER_CONFIG 0x0F
|
||||
#define AD4080_REG_INTERFACE_CONFIG_C 0x10
|
||||
#define AD4080_REG_INTERFACE_STATUS_A 0x11
|
||||
#define AD4080_REG_DEVICE_STATUS 0x14
|
||||
#define AD4080_REG_ADC_DATA_INTF_CONFIG_A 0x15
|
||||
#define AD4080_REG_ADC_DATA_INTF_CONFIG_B 0x16
|
||||
#define AD4080_REG_ADC_DATA_INTF_CONFIG_C 0x17
|
||||
#define AD4080_REG_PWR_CTRL 0x18
|
||||
#define AD4080_REG_GPIO_CONFIG_A 0x19
|
||||
#define AD4080_REG_GPIO_CONFIG_B 0x1A
|
||||
#define AD4080_REG_GPIO_CONFIG_C 0x1B
|
||||
#define AD4080_REG_GENERAL_CONFIG 0x1C
|
||||
#define AD4080_REG_FIFO_WATERMARK_LSB 0x1D
|
||||
#define AD4080_REG_FIFO_WATERMARK_MSB 0x1E
|
||||
#define AD4080_REG_EVENT_HYSTERESIS_LSB 0x1F
|
||||
#define AD4080_REG_EVENT_HYSTERESIS_MSB 0x20
|
||||
#define AD4080_REG_EVENT_DETECTION_HI_LSB 0x21
|
||||
#define AD4080_REG_EVENT_DETECTION_HI_MSB 0x22
|
||||
#define AD4080_REG_EVENT_DETECTION_LO_LSB 0x23
|
||||
#define AD4080_REG_EVENT_DETECTION_LO_MSB 0x24
|
||||
#define AD4080_REG_OFFSET_LSB 0x25
|
||||
#define AD4080_REG_OFFSET_MSB 0x26
|
||||
#define AD4080_REG_GAIN_LSB 0x27
|
||||
#define AD4080_REG_GAIN_MSB 0x28
|
||||
#define AD4080_REG_FILTER_CONFIG 0x29
|
||||
|
||||
/* AD4080_REG_INTERFACE_CONFIG_A Bit Definition */
|
||||
#define AD4080_INTERFACE_CONFIG_A_SW_RESET (BIT(7) | BIT(0))
|
||||
#define AD4080_INTERFACE_CONFIG_A_ADDR_ASC BIT(5)
|
||||
#define AD4080_INTERFACE_CONFIG_A_SDO_ENABLE BIT(4)
|
||||
|
||||
/* AD4080_REG_INTERFACE_CONFIG_B Bit Definition */
|
||||
#define AD4080_INTERFACE_CONFIG_B_SINGLE_INST BIT(7)
|
||||
#define AD4080_INTERFACE_CONFIG_B_SHORT_INST BIT(3)
|
||||
|
||||
/* AD4080_REG_DEVICE_CONFIG Bit Definition */
|
||||
#define AD4080_DEVICE_CONFIG_OPERATING_MODES_MSK GENMASK(1, 0)
|
||||
|
||||
/* AD4080_REG_TRANSFER_CONFIG Bit Definition */
|
||||
#define AD4080_TRANSFER_CONFIG_KEEP_STREAM_LENGTH_VAL BIT(2)
|
||||
|
||||
/* AD4080_REG_INTERFACE_CONFIG_C Bit Definition */
|
||||
#define AD4080_INTERFACE_CONFIG_C_STRICT_REG_ACCESS BIT(5)
|
||||
|
||||
/* AD4080_REG_ADC_DATA_INTF_CONFIG_A Bit Definition */
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_A_RESERVED_CONFIG_A BIT(6)
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN BIT(4)
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES BIT(2)
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_A_DATA_INTF_MODE BIT(0)
|
||||
|
||||
/* AD4080_REG_ADC_DATA_INTF_CONFIG_B Bit Definition */
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK GENMASK(7, 4)
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_SELF_CLK_MODE BIT(3)
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN BIT(0)
|
||||
|
||||
/* AD4080_REG_ADC_DATA_INTF_CONFIG_C Bit Definition */
|
||||
#define AD4080_ADC_DATA_INTF_CONFIG_C_LVDS_VOD_MSK GENMASK(6, 4)
|
||||
|
||||
/* AD4080_REG_PWR_CTRL Bit Definition */
|
||||
#define AD4080_PWR_CTRL_ANA_DIG_LDO_PD BIT(1)
|
||||
#define AD4080_PWR_CTRL_INTF_LDO_PD BIT(0)
|
||||
|
||||
/* AD4080_REG_GPIO_CONFIG_A Bit Definition */
|
||||
#define AD4080_GPIO_CONFIG_A_GPO_1_EN BIT(1)
|
||||
#define AD4080_GPIO_CONFIG_A_GPO_0_EN BIT(0)
|
||||
|
||||
/* AD4080_REG_GPIO_CONFIG_B Bit Definition */
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK GENMASK(7, 4)
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_0_SEL_MSK GENMASK(3, 0)
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_SPI_SDO 0
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_FIFO_FULL 1
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_FIFO_READ_DONE 2
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY 3
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_H_THRESH 4
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_L_THRESH 5
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_STATUS_ALERT 6
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_GPIO_DATA 7
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_FILTER_SYNC 8
|
||||
#define AD4080_GPIO_CONFIG_B_GPIO_EXTERNAL_EVENT 9
|
||||
|
||||
/* AD4080_REG_FIFO_CONFIG Bit Definition */
|
||||
#define AD4080_FIFO_CONFIG_FIFO_MODE_MSK GENMASK(1, 0)
|
||||
|
||||
/* AD4080_REG_FILTER_CONFIG Bit Definition */
|
||||
#define AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK GENMASK(6, 3)
|
||||
#define AD4080_FILTER_CONFIG_FILTER_SEL_MSK GENMASK(1, 0)
|
||||
|
||||
/* Miscellaneous Definitions */
|
||||
#define AD4080_SPI_READ BIT(7)
|
||||
#define AD4080_CHIP_ID GENMASK(2, 0)
|
||||
|
||||
#define AD4080_LVDS_CNV_CLK_CNT_MAX 7
|
||||
|
||||
#define AD4080_MAX_SAMP_FREQ 40000000
|
||||
#define AD4080_MIN_SAMP_FREQ 1250000
|
||||
|
||||
enum ad4080_filter_type {
|
||||
FILTER_NONE,
|
||||
SINC_1,
|
||||
SINC_5,
|
||||
SINC_5_COMP
|
||||
};
|
||||
|
||||
static const unsigned int ad4080_scale_table[][2] = {
|
||||
{ 6000, 0 },
|
||||
};
|
||||
|
||||
static const char *const ad4080_filter_type_iio_enum[] = {
|
||||
[FILTER_NONE] = "none",
|
||||
[SINC_1] = "sinc1",
|
||||
[SINC_5] = "sinc5",
|
||||
[SINC_5_COMP] = "sinc5+pf1",
|
||||
};
|
||||
|
||||
static const int ad4080_dec_rate_avail[] = {
|
||||
2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
|
||||
};
|
||||
|
||||
static const int ad4080_dec_rate_none[] = { 1 };
|
||||
|
||||
static const char * const ad4080_power_supplies[] = {
|
||||
"vdd33", "vdd11", "vddldo", "iovdd", "vrefin",
|
||||
};
|
||||
|
||||
struct ad4080_chip_info {
|
||||
const char *name;
|
||||
unsigned int product_id;
|
||||
int num_scales;
|
||||
const unsigned int (*scale_table)[2];
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned int num_channels;
|
||||
};
|
||||
|
||||
struct ad4080_state {
|
||||
struct regmap *regmap;
|
||||
struct iio_backend *back;
|
||||
const struct ad4080_chip_info *info;
|
||||
/*
|
||||
* Synchronize access to members the of driver state, and ensure
|
||||
* atomicity of consecutive regmap operations.
|
||||
*/
|
||||
struct mutex lock;
|
||||
unsigned int num_lanes;
|
||||
unsigned int dec_rate;
|
||||
unsigned long clk_rate;
|
||||
enum ad4080_filter_type filter_type;
|
||||
bool lvds_cnv_en;
|
||||
};
|
||||
|
||||
static const struct regmap_config ad4080_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.read_flag_mask = BIT(7),
|
||||
.max_register = 0x29,
|
||||
};
|
||||
|
||||
static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg,
|
||||
unsigned int writeval, unsigned int *readval)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (readval)
|
||||
return regmap_read(st->regmap, reg, readval);
|
||||
|
||||
return regmap_write(st->regmap, reg, writeval);
|
||||
}
|
||||
|
||||
static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = (st->info->scale_table[0][0] * 1000000ULL) >>
|
||||
st->info->channels[0].scan_type.realbits;
|
||||
*val = tmp / 1000000;
|
||||
*val2 = tmp % 1000000;
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
|
||||
static unsigned int ad4080_get_dec_rate(struct iio_dev *dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(dev);
|
||||
int ret;
|
||||
unsigned int data;
|
||||
|
||||
ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 1 << (FIELD_GET(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, data) + 1);
|
||||
}
|
||||
|
||||
static int ad4080_set_dec_rate(struct iio_dev *dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(dev);
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
if ((st->filter_type >= SINC_5 && mode >= 512) || mode < 2)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
|
||||
AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
|
||||
FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
|
||||
(ilog2(mode) - 1)));
|
||||
}
|
||||
|
||||
static int ad4080_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long m)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(indio_dev);
|
||||
int dec_rate;
|
||||
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return ad4080_get_scale(st, val, val2);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
dec_rate = ad4080_get_dec_rate(indio_dev, chan);
|
||||
if (dec_rate < 0)
|
||||
return dec_rate;
|
||||
if (st->filter_type == SINC_5_COMP)
|
||||
dec_rate *= 2;
|
||||
if (st->filter_type)
|
||||
*val = DIV_ROUND_CLOSEST(st->clk_rate, dec_rate);
|
||||
else
|
||||
*val = st->clk_rate;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
if (st->filter_type == FILTER_NONE) {
|
||||
*val = 1;
|
||||
} else {
|
||||
*val = ad4080_get_dec_rate(indio_dev, chan);
|
||||
if (*val < 0)
|
||||
return *val;
|
||||
}
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4080_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
if (st->filter_type == FILTER_NONE && val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
return ad4080_set_dec_rate(indio_dev, chan, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad4080_lvds_sync_write(struct ad4080_state *st)
|
||||
{
|
||||
struct device *dev = regmap_get_device(st->regmap);
|
||||
int ret;
|
||||
|
||||
ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
|
||||
AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_backend_interface_data_align(st->back, 10000);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Data alignment process failed\n");
|
||||
|
||||
dev_dbg(dev, "Success: Pattern correct and Locked!\n");
|
||||
return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
|
||||
AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
|
||||
}
|
||||
|
||||
static int ad4080_get_filter_type(struct iio_dev *dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(dev);
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return FIELD_GET(AD4080_FILTER_CONFIG_FILTER_SEL_MSK, data);
|
||||
}
|
||||
|
||||
static int ad4080_set_filter_type(struct iio_dev *dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(dev);
|
||||
int dec_rate;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
dec_rate = ad4080_get_dec_rate(dev, chan);
|
||||
if (dec_rate < 0)
|
||||
return dec_rate;
|
||||
|
||||
if (mode >= SINC_5 && dec_rate >= 512)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_backend_filter_type_set(st->back, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
|
||||
AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
|
||||
FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
|
||||
mode));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->filter_type = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4080_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
switch (st->filter_type) {
|
||||
case FILTER_NONE:
|
||||
*vals = ad4080_dec_rate_none;
|
||||
*length = ARRAY_SIZE(ad4080_dec_rate_none);
|
||||
break;
|
||||
default:
|
||||
*vals = ad4080_dec_rate_avail;
|
||||
*length = st->filter_type >= SINC_5 ?
|
||||
(ARRAY_SIZE(ad4080_dec_rate_avail) - 2) :
|
||||
ARRAY_SIZE(ad4080_dec_rate_avail);
|
||||
break;
|
||||
}
|
||||
*type = IIO_VAL_INT;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info ad4080_iio_info = {
|
||||
.debugfs_reg_access = ad4080_reg_access,
|
||||
.read_raw = ad4080_read_raw,
|
||||
.write_raw = ad4080_write_raw,
|
||||
.read_avail = ad4080_read_avail,
|
||||
};
|
||||
|
||||
static const struct iio_enum ad4080_filter_type_enum = {
|
||||
.items = ad4080_filter_type_iio_enum,
|
||||
.num_items = ARRAY_SIZE(ad4080_filter_type_iio_enum),
|
||||
.set = ad4080_set_filter_type,
|
||||
.get = ad4080_get_filter_type,
|
||||
};
|
||||
|
||||
static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
|
||||
IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad4080_filter_type_enum),
|
||||
IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL,
|
||||
&ad4080_filter_type_enum),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad4080_channel = {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.info_mask_shared_by_all_available =
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.ext_info = ad4080_ext_info,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 20,
|
||||
.storagebits = 32,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ad4080_chip_info ad4080_chip_info = {
|
||||
.name = "ad4080",
|
||||
.product_id = AD4080_CHIP_ID,
|
||||
.scale_table = ad4080_scale_table,
|
||||
.num_scales = ARRAY_SIZE(ad4080_scale_table),
|
||||
.num_channels = 1,
|
||||
.channels = &ad4080_channel,
|
||||
};
|
||||
|
||||
static int ad4080_setup(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad4080_state *st = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(st->regmap);
|
||||
unsigned int id;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
|
||||
AD4080_INTERFACE_CONFIG_A_SW_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
|
||||
AD4080_INTERFACE_CONFIG_A_SDO_ENABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(st->regmap, AD4080_REG_CHIP_TYPE, &id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id != AD4080_CHIP_ID)
|
||||
dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id);
|
||||
|
||||
ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A,
|
||||
AD4080_GPIO_CONFIG_A_GPO_1_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B,
|
||||
FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK,
|
||||
AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_backend_num_lanes_set(st->back, st->num_lanes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!st->lvds_cnv_en)
|
||||
return 0;
|
||||
|
||||
/* Set maximum LVDS Data Transfer Latency */
|
||||
ret = regmap_update_bits(st->regmap,
|
||||
AD4080_REG_ADC_DATA_INTF_CONFIG_B,
|
||||
AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
|
||||
FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
|
||||
AD4080_LVDS_CNV_CLK_CNT_MAX));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (st->num_lanes > 1) {
|
||||
ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
|
||||
AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_set_bits(st->regmap,
|
||||
AD4080_REG_ADC_DATA_INTF_CONFIG_B,
|
||||
AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ad4080_lvds_sync_write(st);
|
||||
}
|
||||
|
||||
static int ad4080_properties_parse(struct ad4080_state *st)
|
||||
{
|
||||
struct device *dev = regmap_get_device(st->regmap);
|
||||
|
||||
st->lvds_cnv_en = device_property_read_bool(dev, "adi,lvds-cnv-enable");
|
||||
|
||||
st->num_lanes = 1;
|
||||
device_property_read_u32(dev, "adi,num-lanes", &st->num_lanes);
|
||||
if (!st->num_lanes || st->num_lanes > 2)
|
||||
return dev_err_probe(dev, -EINVAL,
|
||||
"Invalid 'adi,num-lanes' value: %u",
|
||||
st->num_lanes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad4080_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct device *dev = &spi->dev;
|
||||
struct ad4080_state *st;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev,
|
||||
ARRAY_SIZE(ad4080_power_supplies),
|
||||
ad4080_power_supplies);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to get and enable supplies\n");
|
||||
|
||||
st->regmap = devm_regmap_init_spi(spi, &ad4080_regmap_config);
|
||||
if (IS_ERR(st->regmap))
|
||||
return PTR_ERR(st->regmap);
|
||||
|
||||
st->info = spi_get_device_match_data(spi);
|
||||
if (!st->info)
|
||||
return -ENODEV;
|
||||
|
||||
ret = devm_mutex_init(dev, &st->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->channels = st->info->channels;
|
||||
indio_dev->num_channels = st->info->num_channels;
|
||||
indio_dev->info = &ad4080_iio_info;
|
||||
|
||||
ret = ad4080_properties_parse(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk = devm_clk_get_enabled(&spi->dev, "cnv");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
st->clk_rate = clk_get_rate(clk);
|
||||
|
||||
st->back = devm_iio_backend_get(dev, NULL);
|
||||
if (IS_ERR(st->back))
|
||||
return PTR_ERR(st->back);
|
||||
|
||||
ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_backend_enable(dev, st->back);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad4080_setup(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad4080_id[] = {
|
||||
{ "ad4080", (kernel_ulong_t)&ad4080_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad4080_id);
|
||||
|
||||
static const struct of_device_id ad4080_of_match[] = {
|
||||
{ .compatible = "adi,ad4080", &ad4080_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad4080_of_match);
|
||||
|
||||
static struct spi_driver ad4080_driver = {
|
||||
.driver = {
|
||||
.name = "ad4080",
|
||||
.of_match_table = ad4080_of_match,
|
||||
},
|
||||
.probe = ad4080_probe,
|
||||
.id_table = ad4080_id,
|
||||
};
|
||||
module_spi_driver(ad4080_driver);
|
||||
|
||||
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");
|
||||
MODULE_DESCRIPTION("Analog Devices AD4080");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("IIO_BACKEND");
|
3027
drivers/iio/adc/ad4170-4.c
Normal file
3027
drivers/iio/adc/ad4170-4.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -294,7 +294,6 @@ static int ad4851_scale_fill(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
static int ad4851_set_oversampling_ratio(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int osr)
|
||||
{
|
||||
struct ad4851_state *st = iio_priv(indio_dev);
|
||||
|
@ -321,7 +320,8 @@ static int ad4851_set_oversampling_ratio(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = iio_backend_oversampling_ratio_set(st->back, osr);
|
||||
/* Channel is ignored by the backend being used here */
|
||||
ret = iio_backend_oversampling_ratio_set(st->back, 0, osr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -444,10 +444,12 @@ static int ad4851_setup(struct ad4851_state *st)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->regmap, AD4851_REG_INTERFACE_CONFIG_A,
|
||||
AD4851_SDO_ENABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(st->spi->mode & SPI_3WIRE)) {
|
||||
ret = regmap_write(st->regmap, AD4851_REG_INTERFACE_CONFIG_A,
|
||||
AD4851_SDO_ENABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(st->regmap, AD4851_REG_PRODUCT_ID_L, &product_id);
|
||||
if (ret)
|
||||
|
@ -831,7 +833,7 @@ static int ad4851_write_raw(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
return ad4851_set_calibbias(st, chan->channel, val);
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
return ad4851_set_oversampling_ratio(indio_dev, chan, val);
|
||||
return ad4851_set_oversampling_ratio(indio_dev, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue