mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 13:30:45 -05:00
Merge tag 'iio-for-6.17a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes:
IIO: New device support, features, late breaking fixes and cleanup for 6.17
The normal mixed bag. A few more fixes than usual as I failed to send
them out earlier.
New device support
==================
adi,ad4080
- New driver for this high speed ADC. Includes extensions to iio-backends
necessary to support filter config, variable data lands and data
alignment control.
adi,ad4170-4
- New driver for this 24-bit very feature rich ADC suited for weigh scale
and thermocouple applications.
adi,ad7405
- New driver for this single channel isolated ADC with backend support
(adi-axi-adc)
google,cros_ec_activity
- Add activity detection to the existing set of cros_ec drivers covering
both human body and significant motion detection.
mediatek,mt6359
- Add support for MT6363 and MT6373 PMIC Auxiliary ADCs.
nicera,d3-323-aa
- New driver for this configurable Passive InfraRed sensor.
Device ID only
==============
mediatek,mt7981-auxadc
- Add ID to mt2701 driver as fully compatible with mt7986-auxadc.
rohm,bu79100g
- Add ID to ad7476 driver as fully compatible with TI ADS7866.
Features
========
Core
- New in_voltageY_convdelay to allow for devices to control timing
offsets between sampling different channels.
adi,ad-sigma-delta-library
- Support SPI offload (later fix for missing Kconfig dependency)
adi,ad4851
- SPI 3-wire support.
adi,ad7606
- Power supply control.
- convdelay and calibbias support for calibration purposes.
- gain calibration support based on external filter resistance provided
from device tree.
adi,ad7768-1
- Add output regulator for VCM output, typically used for preconditioning
circuits.
- Add gpio controller for the 4 GPIOs.
- Multiple scan type support to enable 16-bit modes.
- Support synchronization over SPI.
- Filter type and oversampling ratio control.
- Low pass filter cut off read only attribute.
adi,adxl313
- FIFO support
- DC activity, inactivity detection with power-save on inactivity
- AC coupled activity detection
- Documentation for this complex driver.
- debugfs register access.
adi,adxl345
- Sampling frequency and sensor range controls.
bosch,bmi270
- Add step counter support.
invensense,icm42600
- Wake on motion support.
Cleanup and fixes
=================
backend
- Drop unused parameter from iio_backend_ovesampling_ratio_set()
docs
- Fix ABI docs around I and Q modifiers.
treewide
- Switch remaining drives to use maple tree regcache.
- Drop use of DRIVER_NAME style definitions when only used in one
place.
- Drop unused export.h includes.
- Use = { } in place of memset in various drivers.
- Constify various info structures and related.
- Switch some drivers from array of chip_info structures to individual
named structures.
adi,ad-sigma_delta library
- Fix over allocation of scan buffer. (bits/bytes confusion)
- Sort includes and apply iwyu principles to ensure sensible set.
- Use u8 instead of uint8_t
- Replace hard coded type sizes with sizeof() and BITS_TO_BYTES() as
appropriate.
- Factor out setting of read address to reduce duplication.
- Switch to buffer predisable so error handling on buffer enable
functions correctly (balanced against postenable).
adi,ad4000
- Don't use sift_right() on an unsigned value.
adi,ad7173
- Add missing check on spi_setup() succeeding.
- Simplify clock enable disable code using devm_clk_get_enabled()
- Fix channel index for syscalib_mode
- Fix number of configuration slots for some devics.
- Fix the channel used for calibration.
- Fix setting ODR up in probe.
adi,ad7380
- Drop unused oversampling_ratio getter function call as value never
used.
adi,ad7606
- Exit if invalid dt_schema encountered rather than carrying on with
unknown config.
adi,ad7768-1
- Ensure SYNC_IN pulse is long enough.
- Switch sampling_frequency_available to read_avail() callback.
adi,ada4250
- Ensuring a dma-safe buffer for regmap_bulk_read()
- Use a local dev variable to simplify code
- Relax chip ID matching to allow for fallback dt compatibles.
- Make use of devm_regulator_get_enabled_read_voltage() to replace
equivalent code.
- Shuffle elements around in struct to improve logical groupings and
reduce holes.
- Use dev_err_probe()
adi,adxl313
- Use regcache to reduce traffic.
- Factor out enabling of measurement.
adi,adxl345
- Drop irq from struct as only used locally in code
- Simplify measure enable function using regmap_update_bits()
- Replace some magic numbers by units.h defines
- Simplify interrupt mapping code
- Simplify FIFO read out.
adi,axi-dac
- Factor out code to check for bus free to reduce duplication.
avago,apds9306
- Use a helper to get register address in both get and set functions.
bosch,bmi160+bmi270
- Ensure triggers suspended and resumed correctly.
bosch,bmo055
- Fix theoretical OOB acces to hw_xlate array.
freescale,vf610
- Drop -ENOMEM error message as plenty of existing prints if memory
allocation fails.
- Use dev_err_probe() and devm_clk_geT_enabled() to simplify probe().
kionix,kx022a
- Apply include what you use principles to includes.
invensense,itg3200
- Add missing dt-binding for this gyroscope.
invensense,icm42600
- Switch from int64_t and similar to s64 and other kernel types.
- Simplify arrangement of DMA safe buffers and potentially reduce
structure size a little.
invensense,mpu6050
- Reduce duplication in aux read/write code.
- Use sysfs_emit() to replace scnprintf()
murata,irsd200
- Drop duplicate printing of ret in dev_err_probe()
nxp,lpc3220-adc
- Add missing clocks property to dt-binding.
st,spear600
- Convert dt-binding that got left behind in staging to yaml in the main
tree.
st,stm32-adc
- Use dev_fwnode() rather than directly accessing the of_node.
vti,sca3000
- Use direct returns instead of gotos where simple.
Various other minor typo and white space fixes.
* tag 'iio-for-6.17a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (201 commits)
iio: adc: ad_sigma_delta: Select IIO_BUFFER_DMAENGINE and SPI_OFFLOAD
iio: adc: ad7173: fix setting ODR in probe
iio: adc: ad7173: fix calibration channel
iio: adc: ad7173: fix num_slots
iio: adc: ad7173: fix channels index for syscalib_mode
iio: adc: ad_sigma_delta: change to buffer predisable
iio: ABI: fix correctness of I and Q modifiers
iio: Add driver for Nicera D3-323-AA PIR sensor
dt-bindings: iio: proximity: Add Nicera D3-323-AA PIR sensor
dt-bindings: vendor-prefixes: Add Nicera
iio: dac: vf610: Simplify with devm_clk_get_enabled()
iio: adc: vf610: Simplify with dev_err_probe
iio: adc: vf610: Drop -ENOMEM error message
iio: imu: bno055: make bno055_sysfs_attr const
iio: imu: bno055: fix OOB access of hw_xlate array
dt-bindings: iio: adc: Add support for MT7981
iio: accel: kionix-kx022a: Apply approximate iwyu principles to includes
iio: adc: ad4170-4: Add support for weigh scale, thermocouple, and RTD sens
iio: adc: ad4170-4: Add support for internal temperature sensor
iio: adc: ad4170-4: Add GPIO controller support
...
This commit is contained in:
@@ -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
|
||||
@@ -256,6 +265,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:
|
||||
@@ -398,6 +426,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>;
|
||||
};
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -1067,6 +1067,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
|
||||
|
||||
21
MAINTAINERS
21
MAINTAINERS
@@ -1374,6 +1374,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
|
||||
@@ -1383,6 +1391,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>
|
||||
@@ -1481,6 +1497,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>
|
||||
@@ -23535,7 +23552,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)
|
||||
@@ -25194,9 +25210,10 @@ W: https://github.com/srcres258/linux-doc
|
||||
T: git git://github.com/srcres258/linux-doc.git doc-zh-tw
|
||||
F: Documentation/translations/zh_TW/
|
||||
|
||||
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
|
||||
|
||||
@@ -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 @@ static irqreturn_t adxl345_irq_handler(int irq, void *p)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ static void ad7091r5_regmap_init(struct ad7091r_state *st,
|
||||
st->map = devm_regmap_init_i2c(i2c, regmap_conf);
|
||||
}
|
||||
|
||||
static struct ad7091r_init_info ad7091r5_init_info = {
|
||||
static const struct ad7091r_init_info ad7091r5_init_info = {
|
||||
.info_irq = &ad7091r5_chip_info_irq,
|
||||
.info_no_irq = &ad7091r5_chip_info_noirq,
|
||||
.regmap_config = &ad7091r_regmap_config,
|
||||
|
||||
@@ -206,14 +206,14 @@ static int ad7091r8_gpio_setup(struct ad7091r_state *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ad7091r_init_info ad7091r2_init_info = {
|
||||
static const struct ad7091r_init_info ad7091r2_init_info = {
|
||||
.info_no_irq = &ad7091r8_infos[AD7091R2_INFO],
|
||||
.regmap_config = &ad7091r2_reg_conf,
|
||||
.init_adc_regmap = &ad7091r8_regmap_init,
|
||||
.setup = &ad7091r8_gpio_setup
|
||||
};
|
||||
|
||||
static struct ad7091r_init_info ad7091r4_init_info = {
|
||||
static const struct ad7091r_init_info ad7091r4_init_info = {
|
||||
.info_no_irq = &ad7091r8_infos[AD7091R4_INFO],
|
||||
.info_irq = &ad7091r8_infos[AD7091R4_INFO_IRQ],
|
||||
.regmap_config = &ad7091r4_reg_conf,
|
||||
@@ -221,7 +221,7 @@ static struct ad7091r_init_info ad7091r4_init_info = {
|
||||
.setup = &ad7091r8_gpio_setup
|
||||
};
|
||||
|
||||
static struct ad7091r_init_info ad7091r8_init_info = {
|
||||
static const struct ad7091r_init_info ad7091r8_init_info = {
|
||||
.info_no_irq = &ad7091r8_infos[AD7091R8_INFO],
|
||||
.info_irq = &ad7091r8_infos[AD7091R8_INFO_IRQ],
|
||||
.regmap_config = &ad7091r8_reg_conf,
|
||||
|
||||
@@ -94,11 +94,6 @@
|
||||
|
||||
/* AD7124 input sources */
|
||||
|
||||
enum ad7124_ids {
|
||||
ID_AD7124_4,
|
||||
ID_AD7124_8,
|
||||
};
|
||||
|
||||
enum ad7124_ref_sel {
|
||||
AD7124_REFIN1,
|
||||
AD7124_REFIN2,
|
||||
@@ -193,17 +188,16 @@ struct ad7124_state {
|
||||
DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS);
|
||||
};
|
||||
|
||||
static struct ad7124_chip_info ad7124_chip_info_tbl[] = {
|
||||
[ID_AD7124_4] = {
|
||||
.name = "ad7124-4",
|
||||
.chip_id = AD7124_ID_DEVICE_ID_AD7124_4,
|
||||
.num_inputs = 8,
|
||||
},
|
||||
[ID_AD7124_8] = {
|
||||
.name = "ad7124-8",
|
||||
.chip_id = AD7124_ID_DEVICE_ID_AD7124_8,
|
||||
.num_inputs = 16,
|
||||
},
|
||||
static const struct ad7124_chip_info ad7124_4_chip_info = {
|
||||
.name = "ad7124-4",
|
||||
.chip_id = AD7124_ID_DEVICE_ID_AD7124_4,
|
||||
.num_inputs = 8,
|
||||
};
|
||||
|
||||
static const struct ad7124_chip_info ad7124_8_chip_info = {
|
||||
.name = "ad7124-8",
|
||||
.chip_id = AD7124_ID_DEVICE_ID_AD7124_8,
|
||||
.num_inputs = 16,
|
||||
};
|
||||
|
||||
static int ad7124_find_closest_match(const int *array,
|
||||
@@ -1341,17 +1335,15 @@ static int ad7124_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7124_of_match[] = {
|
||||
{ .compatible = "adi,ad7124-4",
|
||||
.data = &ad7124_chip_info_tbl[ID_AD7124_4], },
|
||||
{ .compatible = "adi,ad7124-8",
|
||||
.data = &ad7124_chip_info_tbl[ID_AD7124_8], },
|
||||
{ .compatible = "adi,ad7124-4", .data = &ad7124_4_chip_info },
|
||||
{ .compatible = "adi,ad7124-8", .data = &ad7124_8_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7124_of_match);
|
||||
|
||||
static const struct spi_device_id ad71124_ids[] = {
|
||||
{ "ad7124-4", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_4] },
|
||||
{ "ad7124-8", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_8] },
|
||||
{ "ad7124-4", (kernel_ulong_t)&ad7124_4_chip_info },
|
||||
{ "ad7124-8", (kernel_ulong_t)&ad7124_8_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad71124_ids);
|
||||
|
||||
@@ -228,7 +228,6 @@ struct ad7173_state {
|
||||
struct ida cfg_slots_status;
|
||||
unsigned long long config_usage_counter;
|
||||
unsigned long long *config_cnts;
|
||||
struct clk *ext_clk;
|
||||
struct clk_hw int_clk_hw;
|
||||
struct regmap *reg_gpiocon_regmap;
|
||||
struct gpio_regmap *gpio_regmap;
|
||||
@@ -319,7 +318,7 @@ static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->channels[chan->channel].syscalib_mode = mode;
|
||||
st->channels[chan->address].syscalib_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -329,7 +328,7 @@ static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct ad7173_state *st = iio_priv(indio_dev);
|
||||
|
||||
return st->channels[chan->channel].syscalib_mode;
|
||||
return st->channels[chan->address].syscalib_mode;
|
||||
}
|
||||
|
||||
static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
|
||||
@@ -348,7 +347,7 @@ static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
mode = st->channels[chan->channel].syscalib_mode;
|
||||
mode = st->channels[chan->address].syscalib_mode;
|
||||
if (sys_calib) {
|
||||
if (mode == AD7173_SYSCALIB_ZERO_SCALE)
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO,
|
||||
@@ -392,13 +391,12 @@ static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_d
|
||||
if (indio_dev->channels[i].type != IIO_VOLTAGE)
|
||||
continue;
|
||||
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain);
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (st->info->has_internal_fs_calibration) {
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL,
|
||||
st->channels[i].ain);
|
||||
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL, i);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -772,10 +770,26 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_8_slots = {
|
||||
.num_slots = 8,
|
||||
};
|
||||
|
||||
static const struct ad_sigma_delta_info ad7173_sigma_delta_info_16_slots = {
|
||||
.set_channel = ad7173_set_channel,
|
||||
.append_status = ad7173_append_status,
|
||||
.disable_all = ad7173_disable_all,
|
||||
.disable_one = ad7173_disable_one,
|
||||
.set_mode = ad7173_set_mode,
|
||||
.has_registers = true,
|
||||
.has_named_irqs = true,
|
||||
.addr_shift = 0,
|
||||
.read_mask = BIT(6),
|
||||
.status_ch_mask = GENMASK(3, 0),
|
||||
.data_reg = AD7173_REG_DATA,
|
||||
.num_resetclks = 64,
|
||||
.num_slots = 16,
|
||||
};
|
||||
|
||||
static const struct ad7173_device_info ad4111_device_info = {
|
||||
.name = "ad4111",
|
||||
.id = AD4111_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in_div = 8,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -797,7 +811,7 @@ static const struct ad7173_device_info ad4111_device_info = {
|
||||
static const struct ad7173_device_info ad4112_device_info = {
|
||||
.name = "ad4112",
|
||||
.id = AD4112_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in_div = 8,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -818,7 +832,7 @@ static const struct ad7173_device_info ad4112_device_info = {
|
||||
static const struct ad7173_device_info ad4113_device_info = {
|
||||
.name = "ad4113",
|
||||
.id = AD4113_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in_div = 8,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -837,7 +851,7 @@ static const struct ad7173_device_info ad4113_device_info = {
|
||||
static const struct ad7173_device_info ad4114_device_info = {
|
||||
.name = "ad4114",
|
||||
.id = AD4114_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in_div = 16,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -856,7 +870,7 @@ static const struct ad7173_device_info ad4114_device_info = {
|
||||
static const struct ad7173_device_info ad4115_device_info = {
|
||||
.name = "ad4115",
|
||||
.id = AD4115_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in_div = 16,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -875,7 +889,7 @@ static const struct ad7173_device_info ad4115_device_info = {
|
||||
static const struct ad7173_device_info ad4116_device_info = {
|
||||
.name = "ad4116",
|
||||
.id = AD4116_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in_div = 11,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -894,7 +908,7 @@ static const struct ad7173_device_info ad4116_device_info = {
|
||||
static const struct ad7173_device_info ad7172_2_device_info = {
|
||||
.name = "ad7172-2",
|
||||
.id = AD7172_2_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_4_slots,
|
||||
.num_voltage_in = 5,
|
||||
.num_channels = 4,
|
||||
.num_configs = 4,
|
||||
@@ -927,7 +941,7 @@ static const struct ad7173_device_info ad7172_4_device_info = {
|
||||
static const struct ad7173_device_info ad7173_8_device_info = {
|
||||
.name = "ad7173-8",
|
||||
.id = AD7173_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in = 17,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -944,7 +958,7 @@ static const struct ad7173_device_info ad7173_8_device_info = {
|
||||
static const struct ad7173_device_info ad7175_2_device_info = {
|
||||
.name = "ad7175-2",
|
||||
.id = AD7175_2_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_4_slots,
|
||||
.num_voltage_in = 5,
|
||||
.num_channels = 4,
|
||||
.num_configs = 4,
|
||||
@@ -961,7 +975,7 @@ static const struct ad7173_device_info ad7175_2_device_info = {
|
||||
static const struct ad7173_device_info ad7175_8_device_info = {
|
||||
.name = "ad7175-8",
|
||||
.id = AD7175_8_ID,
|
||||
.sd_info = &ad7173_sigma_delta_info_8_slots,
|
||||
.sd_info = &ad7173_sigma_delta_info_16_slots,
|
||||
.num_voltage_in = 17,
|
||||
.num_channels = 16,
|
||||
.num_configs = 8,
|
||||
@@ -1344,11 +1358,6 @@ static void ad7173_disable_regulators(void *data)
|
||||
regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
|
||||
}
|
||||
|
||||
static void ad7173_clk_disable_unprepare(void *clk)
|
||||
{
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
static unsigned long ad7173_sel_clk(struct ad7173_state *st,
|
||||
unsigned int clk_sel)
|
||||
{
|
||||
@@ -1580,6 +1589,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
|
||||
chan_st_priv->cfg.bipolar = false;
|
||||
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
|
||||
chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF;
|
||||
chan_st_priv->cfg.odr = st->info->odr_start_value;
|
||||
chan_st_priv->cfg.openwire_comp_chan = -1;
|
||||
st->adc_mode |= AD7173_ADC_MODE_REF_EN;
|
||||
if (st->info->data_reg_only_16bit)
|
||||
@@ -1646,7 +1656,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
|
||||
chan->scan_index = chan_index;
|
||||
chan->channel = ain[0];
|
||||
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
|
||||
chan_st_priv->cfg.odr = 0;
|
||||
chan_st_priv->cfg.odr = st->info->odr_start_value;
|
||||
chan_st_priv->cfg.openwire_comp_chan = -1;
|
||||
|
||||
chan_st_priv->cfg.bipolar = fwnode_property_read_bool(child, "bipolar");
|
||||
@@ -1718,22 +1728,14 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
|
||||
AD7173_ADC_MODE_CLOCKSEL_INT);
|
||||
ad7173_register_clk_provider(indio_dev);
|
||||
} else {
|
||||
struct clk *clk;
|
||||
|
||||
st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_CLOCKSEL_MASK,
|
||||
AD7173_ADC_MODE_CLOCKSEL_EXT + ret);
|
||||
st->ext_clk = devm_clk_get(dev, ad7173_clk_sel[ret]);
|
||||
if (IS_ERR(st->ext_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(st->ext_clk),
|
||||
clk = devm_clk_get_enabled(dev, ad7173_clk_sel[ret]);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk),
|
||||
"Failed to get external clock\n");
|
||||
|
||||
ret = clk_prepare_enable(st->ext_clk);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable external clock\n");
|
||||
|
||||
ret = devm_add_action_or_reset(dev, ad7173_clk_disable_unprepare,
|
||||
st->ext_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ad7173_fw_parse_channel_config(indio_dev);
|
||||
@@ -1765,7 +1767,9 @@ static int ad7173_probe(struct spi_device *spi)
|
||||
indio_dev->info = &ad7173_info;
|
||||
|
||||
spi->mode = SPI_MODE_3;
|
||||
spi_setup(spi);
|
||||
ret = spi_setup(spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad_sd_init(&st->sd, indio_dev, spi, st->info->sd_info);
|
||||
if (ret)
|
||||
|
||||
@@ -1165,7 +1165,6 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
|
||||
struct spi_transfer *xfer = &st->offload_xfer;
|
||||
struct device *dev = &st->spi->dev;
|
||||
const struct iio_scan_type *scan_type;
|
||||
int oversampling_ratio;
|
||||
int ret;
|
||||
|
||||
scan_type = iio_get_current_scan_type(indio_dev,
|
||||
@@ -1195,10 +1194,6 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
|
||||
}
|
||||
}
|
||||
|
||||
ret = ad7380_get_osr(st, &oversampling_ratio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xfer->bits_per_word = scan_type->realbits;
|
||||
xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
|
||||
xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels;
|
||||
|
||||
253
drivers/iio/adc/ad7405.c
Normal file
253
drivers/iio/adc/ad7405.c
Normal file
@@ -0,0 +1,253 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Analog Devices AD7405 driver
|
||||
*
|
||||
* Copyright 2025 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/iio/backend.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
static const unsigned int ad7405_dec_rates_range[] = {
|
||||
32, 1, 4096,
|
||||
};
|
||||
|
||||
struct ad7405_chip_info {
|
||||
const char *name;
|
||||
const unsigned int full_scale_mv;
|
||||
};
|
||||
|
||||
struct ad7405_state {
|
||||
struct iio_backend *back;
|
||||
const struct ad7405_chip_info *info;
|
||||
unsigned int ref_frequency;
|
||||
unsigned int dec_rate;
|
||||
};
|
||||
|
||||
static int ad7405_set_dec_rate(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
unsigned int dec_rate)
|
||||
{
|
||||
struct ad7405_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (dec_rate > 4096 || dec_rate < 32)
|
||||
return -EINVAL;
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
|
||||
ret = iio_backend_oversampling_ratio_set(st->back, chan->scan_index, dec_rate);
|
||||
iio_device_release_direct(indio_dev);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st->dec_rate = dec_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7405_read_raw(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, int *val,
|
||||
int *val2, long info)
|
||||
{
|
||||
struct ad7405_state *st = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->info->full_scale_mv;
|
||||
*val2 = indio_dev->channels[0].scan_type.realbits - 1;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*val = st->dec_rate;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, st->dec_rate);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = -(1 << (indio_dev->channels[0].scan_type.realbits - 1));
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7405_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long info)
|
||||
{
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
if (val < 0)
|
||||
return -EINVAL;
|
||||
return ad7405_set_dec_rate(indio_dev, chan, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7405_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long info)
|
||||
{
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*vals = ad7405_dec_rates_range;
|
||||
*type = IIO_VAL_INT;
|
||||
return IIO_AVAIL_RANGE;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info ad7405_iio_info = {
|
||||
.read_raw = &ad7405_read_raw,
|
||||
.write_raw = &ad7405_write_raw,
|
||||
.read_avail = &ad7405_read_avail,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7405_channel = {
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
.info_mask_shared_by_all = IIO_CHAN_INFO_SAMP_FREQ |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.info_mask_shared_by_all_available =
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.channel2 = 1,
|
||||
.differential = 1,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ad7405_chip_info ad7405_chip_info = {
|
||||
.name = "ad7405",
|
||||
.full_scale_mv = 320,
|
||||
};
|
||||
|
||||
static const struct ad7405_chip_info adum7701_chip_info = {
|
||||
.name = "adum7701",
|
||||
.full_scale_mv = 320,
|
||||
};
|
||||
|
||||
static const struct ad7405_chip_info adum7702_chip_info = {
|
||||
.name = "adum7702",
|
||||
.full_scale_mv = 64,
|
||||
};
|
||||
|
||||
static const struct ad7405_chip_info adum7703_chip_info = {
|
||||
.name = "adum7703",
|
||||
.full_scale_mv = 320,
|
||||
};
|
||||
|
||||
static const char * const ad7405_power_supplies[] = {
|
||||
"vdd1", "vdd2",
|
||||
};
|
||||
|
||||
static int ad7405_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad7405_state *st;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
st->info = device_get_match_data(dev);
|
||||
if (!st->info)
|
||||
return dev_err_probe(dev, -EINVAL, "no chip info\n");
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad7405_power_supplies),
|
||||
ad7405_power_supplies);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to get and enable supplies");
|
||||
|
||||
clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
st->ref_frequency = clk_get_rate(clk);
|
||||
if (!st->ref_frequency)
|
||||
return -EINVAL;
|
||||
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->channels = &ad7405_channel;
|
||||
indio_dev->num_channels = 1;
|
||||
indio_dev->info = &ad7405_iio_info;
|
||||
|
||||
st->back = devm_iio_backend_get(dev, NULL);
|
||||
if (IS_ERR(st->back))
|
||||
return dev_err_probe(dev, PTR_ERR(st->back),
|
||||
"failed to get IIO backend");
|
||||
|
||||
ret = iio_backend_chan_enable(st->back, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* Set 256 decimation rate. The default value in the AXI_ADC register
|
||||
* is 0, so we set the register with a decimation rate value that is
|
||||
* functional for all parts.
|
||||
*/
|
||||
ret = ad7405_set_dec_rate(indio_dev, &indio_dev->channels[0], 256);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7405_of_match[] = {
|
||||
{ .compatible = "adi,ad7405", .data = &ad7405_chip_info, },
|
||||
{ .compatible = "adi,adum7701", .data = &adum7701_chip_info, },
|
||||
{ .compatible = "adi,adum7702", .data = &adum7702_chip_info, },
|
||||
{ .compatible = "adi,adum7703", .data = &adum7703_chip_info, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ad7405_of_match);
|
||||
|
||||
static struct platform_driver ad7405_driver = {
|
||||
.driver = {
|
||||
.name = "ad7405",
|
||||
.of_match_table = ad7405_of_match,
|
||||
},
|
||||
.probe = ad7405_probe,
|
||||
};
|
||||
module_platform_driver(ad7405_driver);
|
||||
|
||||
MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
|
||||
MODULE_AUTHOR("Pop Ioan Daniel <pop.ioan-daniel@analog.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD7405 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS("IIO_BACKEND");
|
||||
@@ -435,6 +435,13 @@ static const struct spi_device_id ad7476_id[] = {
|
||||
{ "ads7866", ID_ADS7866 },
|
||||
{ "ads7867", ID_ADS7867 },
|
||||
{ "ads7868", ID_ADS7868 },
|
||||
/*
|
||||
* The ROHM BU79100G is identical to the TI's ADS7866 from the software
|
||||
* point of view. The binding document mandates the ADS7866 to be
|
||||
* marked as a fallback for the BU79100G, but we still need the SPI ID
|
||||
* here to make the module loading work.
|
||||
*/
|
||||
{ "bu79100g", ID_ADS7866 },
|
||||
{ "ltc2314-14", ID_LTC2314_14 },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
#include "ad7606.h"
|
||||
|
||||
#define AD7606_CALIB_GAIN_MIN 0
|
||||
#define AD7606_CALIB_GAIN_STEP 1024
|
||||
#define AD7606_CALIB_GAIN_MAX (63 * AD7606_CALIB_GAIN_STEP)
|
||||
|
||||
/*
|
||||
* Scales are computed as 5000/32768 and 10000/32768 respectively,
|
||||
* so that when applied to the raw values they provide mV values.
|
||||
@@ -95,6 +99,22 @@ static const unsigned int ad7616_oversampling_avail[8] = {
|
||||
1, 2, 4, 8, 16, 32, 64, 128,
|
||||
};
|
||||
|
||||
static const int ad7606_calib_offset_avail[3] = {
|
||||
-128, 1, 127,
|
||||
};
|
||||
|
||||
static const int ad7606c_18bit_calib_offset_avail[3] = {
|
||||
-512, 4, 508,
|
||||
};
|
||||
|
||||
static const int ad7606b_calib_phase_avail[][2] = {
|
||||
{ 0, 0 }, { 0, 1250 }, { 0, 318750 },
|
||||
};
|
||||
|
||||
static const int ad7606c_calib_phase_avail[][2] = {
|
||||
{ 0, 0 }, { 0, 1000 }, { 0, 255000 },
|
||||
};
|
||||
|
||||
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan);
|
||||
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
@@ -164,6 +184,9 @@ const struct ad7606_chip_info ad7606b_info = {
|
||||
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
|
||||
.sw_setup_cb = ad7606b_sw_mode_setup,
|
||||
.offload_storagebits = 32,
|
||||
.calib_gain_avail = true,
|
||||
.calib_offset_avail = ad7606_calib_offset_avail,
|
||||
.calib_phase_avail = ad7606b_calib_phase_avail,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
|
||||
|
||||
@@ -177,6 +200,9 @@ const struct ad7606_chip_info ad7606c_16_info = {
|
||||
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
|
||||
.sw_setup_cb = ad7606b_sw_mode_setup,
|
||||
.offload_storagebits = 32,
|
||||
.calib_gain_avail = true,
|
||||
.calib_offset_avail = ad7606_calib_offset_avail,
|
||||
.calib_phase_avail = ad7606c_calib_phase_avail,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
|
||||
|
||||
@@ -226,6 +252,9 @@ const struct ad7606_chip_info ad7606c_18_info = {
|
||||
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
|
||||
.sw_setup_cb = ad7606b_sw_mode_setup,
|
||||
.offload_storagebits = 32,
|
||||
.calib_gain_avail = true,
|
||||
.calib_offset_avail = ad7606c_18bit_calib_offset_avail,
|
||||
.calib_phase_avail = ad7606c_calib_phase_avail,
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
|
||||
|
||||
@@ -261,21 +290,21 @@ static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
|
||||
struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
|
||||
|
||||
if (!st->sw_mode_en) {
|
||||
/* tied to logic low, analog input range is +/- 5V */
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_16bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
|
||||
ci->range = 0;
|
||||
ci->scale_avail = ad7606_16bit_hw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scale of 0.076293 is only available in sw mode */
|
||||
/* After reset, in software mode, ±10 V is set by default */
|
||||
cs->range = 2;
|
||||
cs->scale_avail = ad7606_16bit_sw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
|
||||
ci->range = 2;
|
||||
ci->scale_avail = ad7606_16bit_sw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -284,6 +313,7 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
|
||||
bool *bipolar, bool *differential)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_info *ci;
|
||||
unsigned int num_channels = st->chip_info->num_adc_channels;
|
||||
struct device *dev = st->dev;
|
||||
int ret;
|
||||
@@ -297,15 +327,13 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (ret)
|
||||
continue;
|
||||
return ret;
|
||||
|
||||
/* channel number (here) is from 1 to num_channels */
|
||||
if (reg < 1 || reg > num_channels) {
|
||||
dev_warn(dev,
|
||||
"Invalid channel number (ignoring): %d\n", reg);
|
||||
continue;
|
||||
}
|
||||
if (reg < 1 || reg > num_channels)
|
||||
return -EINVAL;
|
||||
|
||||
/* Loop until we are in the right channel. */
|
||||
if (reg != (ch + 1))
|
||||
continue;
|
||||
|
||||
@@ -329,6 +357,14 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ci = &st->chan_info[reg - 1];
|
||||
|
||||
ci->r_gain = 0;
|
||||
ret = fwnode_property_read_u32(child, "adi,rfilter-ohms",
|
||||
&ci->r_gain);
|
||||
if (ret == 0 && ci->r_gain > AD7606_CALIB_GAIN_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -339,14 +375,14 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
|
||||
struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
|
||||
bool bipolar, differential;
|
||||
int ret;
|
||||
|
||||
if (!st->sw_mode_en) {
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_18bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
|
||||
ci->range = 0;
|
||||
ci->scale_avail = ad7606_18bit_hw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -356,12 +392,12 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
if (differential) {
|
||||
cs->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ci->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
|
||||
ci->num_scales =
|
||||
ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail);
|
||||
/* Bipolar differential ranges start at 8 (b1000) */
|
||||
cs->reg_offset = 8;
|
||||
cs->range = 1;
|
||||
ci->reg_offset = 8;
|
||||
ci->range = 1;
|
||||
chan->differential = 1;
|
||||
chan->channel2 = chan->channel;
|
||||
|
||||
@@ -371,23 +407,23 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
chan->differential = 0;
|
||||
|
||||
if (bipolar) {
|
||||
cs->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ci->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
|
||||
ci->num_scales =
|
||||
ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail);
|
||||
/* Bipolar single-ended ranges start at 0 (b0000) */
|
||||
cs->reg_offset = 0;
|
||||
cs->range = 3;
|
||||
ci->reg_offset = 0;
|
||||
ci->range = 3;
|
||||
chan->scan_type.sign = 's';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cs->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ci->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
|
||||
ci->num_scales =
|
||||
ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail);
|
||||
/* Unipolar single-ended ranges start at 5 (b0101) */
|
||||
cs->reg_offset = 5;
|
||||
cs->range = 1;
|
||||
ci->reg_offset = 5;
|
||||
ci->range = 1;
|
||||
chan->scan_type.sign = 'u';
|
||||
|
||||
return 0;
|
||||
@@ -397,14 +433,14 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
|
||||
struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
|
||||
bool bipolar, differential;
|
||||
int ret;
|
||||
|
||||
if (!st->sw_mode_en) {
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_16bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
|
||||
ci->range = 0;
|
||||
ci->scale_avail = ad7606_16bit_hw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -414,12 +450,12 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
if (differential) {
|
||||
cs->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ci->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
|
||||
ci->num_scales =
|
||||
ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail);
|
||||
/* Bipolar differential ranges start at 8 (b1000) */
|
||||
cs->reg_offset = 8;
|
||||
cs->range = 1;
|
||||
ci->reg_offset = 8;
|
||||
ci->range = 1;
|
||||
chan->differential = 1;
|
||||
chan->channel2 = chan->channel;
|
||||
chan->scan_type.sign = 's';
|
||||
@@ -430,23 +466,23 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
chan->differential = 0;
|
||||
|
||||
if (bipolar) {
|
||||
cs->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ci->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
|
||||
ci->num_scales =
|
||||
ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail);
|
||||
/* Bipolar single-ended ranges start at 0 (b0000) */
|
||||
cs->reg_offset = 0;
|
||||
cs->range = 3;
|
||||
ci->reg_offset = 0;
|
||||
ci->range = 3;
|
||||
chan->scan_type.sign = 's';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cs->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
|
||||
cs->num_scales =
|
||||
ci->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
|
||||
ci->num_scales =
|
||||
ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail);
|
||||
/* Unipolar single-ended ranges start at 5 (b0101) */
|
||||
cs->reg_offset = 5;
|
||||
cs->range = 1;
|
||||
ci->reg_offset = 5;
|
||||
ci->range = 1;
|
||||
chan->scan_type.sign = 'u';
|
||||
|
||||
return 0;
|
||||
@@ -456,11 +492,11 @@ static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
|
||||
struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
|
||||
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7607_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
|
||||
ci->range = 0;
|
||||
ci->scale_avail = ad7607_hw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -468,11 +504,11 @@ static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
|
||||
struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
|
||||
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7606_18bit_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
|
||||
ci->range = 0;
|
||||
ci->scale_avail = ad7606_18bit_hw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -480,11 +516,11 @@ static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *chan)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
|
||||
struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
|
||||
|
||||
cs->range = 0;
|
||||
cs->scale_avail = ad7609_hw_scale_avail;
|
||||
cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
|
||||
ci->range = 0;
|
||||
ci->scale_avail = ad7609_hw_scale_avail;
|
||||
ci->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -681,6 +717,40 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7606_get_calib_offset(struct ad7606_state *st, int ch, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = st->bops->reg_read(st, AD7606_CALIB_OFFSET(ch));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = st->chip_info->calib_offset_avail[0] +
|
||||
ret * st->chip_info->calib_offset_avail[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_get_calib_phase(struct ad7606_state *st, int ch, int *val,
|
||||
int *val2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = st->bops->reg_read(st, AD7606_CALIB_PHASE(ch));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = 0;
|
||||
|
||||
/*
|
||||
* ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
|
||||
* ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
|
||||
*/
|
||||
*val2 = ret * st->chip_info->calib_phase_avail[1][1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val,
|
||||
@@ -689,7 +759,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
|
||||
{
|
||||
int ret, ch = 0;
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs;
|
||||
struct ad7606_chan_info *ci;
|
||||
struct pwm_state cnvst_pwm_state;
|
||||
|
||||
switch (m) {
|
||||
@@ -704,9 +774,9 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->scan_index;
|
||||
cs = &st->chan_scales[ch];
|
||||
*val = cs->scale_avail[cs->range][0];
|
||||
*val2 = cs->scale_avail[cs->range][1];
|
||||
ci = &st->chan_info[ch];
|
||||
*val = ci->scale_avail[ci->range][0];
|
||||
*val2 = ci->scale_avail[ci->range][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*val = st->oversampling;
|
||||
@@ -715,6 +785,22 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
|
||||
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
|
||||
*val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
ret = ad7606_get_calib_offset(st, chan->scan_index, val);
|
||||
iio_device_release_direct(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CONVDELAY:
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
ret = ad7606_get_calib_phase(st, chan->scan_index, val, val2);
|
||||
iio_device_release_direct(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -725,12 +811,12 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs = &st->chan_scales[0];
|
||||
const unsigned int (*vals)[2] = cs->scale_avail;
|
||||
struct ad7606_chan_info *ci = &st->chan_info[0];
|
||||
const unsigned int (*vals)[2] = ci->scale_avail;
|
||||
unsigned int i;
|
||||
size_t len = 0;
|
||||
|
||||
for (i = 0; i < cs->num_scales; i++)
|
||||
for (i = 0; i < ci->num_scales; i++)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
|
||||
vals[i][0], vals[i][1]);
|
||||
buf[len - 1] = '\n';
|
||||
@@ -765,6 +851,64 @@ static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_set_calib_offset(struct ad7606_state *st, int ch, int val)
|
||||
{
|
||||
int start_val, step_val, stop_val;
|
||||
int offset;
|
||||
|
||||
start_val = st->chip_info->calib_offset_avail[0];
|
||||
step_val = st->chip_info->calib_offset_avail[1];
|
||||
stop_val = st->chip_info->calib_offset_avail[2];
|
||||
|
||||
if (val < start_val || val > stop_val)
|
||||
return -EINVAL;
|
||||
|
||||
offset = (val - start_val) / step_val;
|
||||
|
||||
return st->bops->reg_write(st, AD7606_CALIB_OFFSET(ch), offset);
|
||||
}
|
||||
|
||||
static int ad7606_set_calib_phase(struct ad7606_state *st, int ch, int val,
|
||||
int val2)
|
||||
{
|
||||
int wreg, start_ns, step_ns, stop_ns;
|
||||
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
start_ns = st->chip_info->calib_phase_avail[0][1];
|
||||
step_ns = st->chip_info->calib_phase_avail[1][1];
|
||||
stop_ns = st->chip_info->calib_phase_avail[2][1];
|
||||
|
||||
/*
|
||||
* ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
|
||||
* ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
|
||||
*/
|
||||
if (val2 < start_ns || val2 > stop_ns)
|
||||
return -EINVAL;
|
||||
|
||||
wreg = val2 / step_ns;
|
||||
|
||||
return st->bops->reg_write(st, AD7606_CALIB_PHASE(ch), wreg);
|
||||
}
|
||||
|
||||
static int ad7606_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, long info)
|
||||
{
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CONVDELAY:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
@@ -773,7 +917,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
unsigned int scale_avail_uv[AD760X_MAX_SCALES];
|
||||
struct ad7606_chan_scale *cs;
|
||||
struct ad7606_chan_info *ci;
|
||||
int i, ret, ch = 0;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
@@ -782,21 +926,21 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->scan_index;
|
||||
cs = &st->chan_scales[ch];
|
||||
for (i = 0; i < cs->num_scales; i++) {
|
||||
scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO +
|
||||
cs->scale_avail[i][1];
|
||||
ci = &st->chan_info[ch];
|
||||
for (i = 0; i < ci->num_scales; i++) {
|
||||
scale_avail_uv[i] = ci->scale_avail[i][0] * MICRO +
|
||||
ci->scale_avail[i][1];
|
||||
}
|
||||
val = (val * MICRO) + val2;
|
||||
i = find_closest(val, scale_avail_uv, cs->num_scales);
|
||||
i = find_closest(val, scale_avail_uv, ci->num_scales);
|
||||
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
|
||||
ret = st->write_scale(indio_dev, ch, i + ci->reg_offset);
|
||||
iio_device_release_direct(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cs->range = i;
|
||||
ci->range = i;
|
||||
|
||||
return 0;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
@@ -818,6 +962,18 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
if (val < 0 && val2 != 0)
|
||||
return -EINVAL;
|
||||
return ad7606_set_sampling_freq(st, val);
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
ret = ad7606_set_calib_offset(st, chan->scan_index, val);
|
||||
iio_device_release_direct(indio_dev);
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_CONVDELAY:
|
||||
if (!iio_device_claim_direct(indio_dev))
|
||||
return -EBUSY;
|
||||
ret = ad7606_set_calib_phase(st, chan->scan_index, val, val2);
|
||||
iio_device_release_direct(indio_dev);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -975,7 +1131,7 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
|
||||
long info)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
struct ad7606_chan_scale *cs;
|
||||
struct ad7606_chan_info *ci;
|
||||
unsigned int ch = 0;
|
||||
|
||||
switch (info) {
|
||||
@@ -990,12 +1146,20 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
|
||||
if (st->sw_mode_en)
|
||||
ch = chan->scan_index;
|
||||
|
||||
cs = &st->chan_scales[ch];
|
||||
*vals = (int *)cs->scale_avail;
|
||||
*length = cs->num_scales * 2;
|
||||
ci = &st->chan_info[ch];
|
||||
*vals = (int *)ci->scale_avail;
|
||||
*length = ci->num_scales * 2;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
*vals = st->chip_info->calib_offset_avail;
|
||||
*type = IIO_VAL_INT;
|
||||
return IIO_AVAIL_RANGE;
|
||||
case IIO_CHAN_INFO_CONVDELAY:
|
||||
*vals = (const int *)st->chip_info->calib_phase_avail;
|
||||
*type = IIO_VAL_INT_PLUS_NANO;
|
||||
return IIO_AVAIL_RANGE;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1058,6 +1222,7 @@ static const struct iio_info ad7606_info_sw_mode = {
|
||||
.read_raw = &ad7606_read_raw,
|
||||
.write_raw = &ad7606_write_raw,
|
||||
.read_avail = &ad7606_read_avail,
|
||||
.write_raw_get_fmt = ad7606_write_raw_get_fmt,
|
||||
.debugfs_reg_access = &ad7606_reg_access,
|
||||
.validate_trigger = &ad7606_validate_trigger,
|
||||
.update_scan_mode = &ad7606_update_scan_mode,
|
||||
@@ -1203,6 +1368,23 @@ static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
|
||||
return st->bops->sw_mode_config(indio_dev);
|
||||
}
|
||||
|
||||
static int ad7606_set_gain_calib(struct ad7606_state *st)
|
||||
{
|
||||
struct ad7606_chan_info *ci;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < st->chip_info->num_adc_channels; i++) {
|
||||
ci = &st->chan_info[i];
|
||||
ret = st->bops->reg_write(st, AD7606_CALIB_GAIN(i),
|
||||
DIV_ROUND_CLOSEST(ci->r_gain,
|
||||
AD7606_CALIB_GAIN_STEP));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7606_probe_channels(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
@@ -1250,6 +1432,15 @@ static int ad7606_probe_channels(struct iio_dev *indio_dev)
|
||||
chan->info_mask_separate_available |=
|
||||
BIT(IIO_CHAN_INFO_SCALE);
|
||||
|
||||
if (st->chip_info->calib_offset_avail) {
|
||||
chan->info_mask_separate |=
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) |
|
||||
BIT(IIO_CHAN_INFO_CONVDELAY);
|
||||
chan->info_mask_separate_available |=
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) |
|
||||
BIT(IIO_CHAN_INFO_CONVDELAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* All chips with software mode support oversampling,
|
||||
* so we skip the oversampling_available check. And the
|
||||
@@ -1330,6 +1521,16 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable specified AVcc supply\n");
|
||||
|
||||
ret = devm_regulator_get_enable(dev, "vdrive");
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable Vdrive supply\n");
|
||||
|
||||
ret = devm_regulator_get_enable_optional(dev, "refin");
|
||||
if (ret && ret != -ENODEV)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable REFIN supply\n");
|
||||
|
||||
st->chip_info = chip_info;
|
||||
|
||||
if (st->chip_info->oversampling_num) {
|
||||
@@ -1462,6 +1663,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
st->chip_info->sw_setup_cb(indio_dev);
|
||||
}
|
||||
|
||||
if (st->sw_mode_en && st->chip_info->calib_gain_avail) {
|
||||
ret = ad7606_set_gain_calib(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");
|
||||
@@ -1487,7 +1694,7 @@ static int ad7606_resume(struct device *dev)
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (st->gpio_standby) {
|
||||
gpiod_set_value(st->gpio_range, st->chan_scales[0].range);
|
||||
gpiod_set_value(st->gpio_range, st->chan_info[0].range);
|
||||
gpiod_set_value(st->gpio_standby, 1);
|
||||
ad7606_reset(st);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1))
|
||||
#define AD7606_OS_MODE 0x08
|
||||
|
||||
#define AD7606_CALIB_GAIN(ch) (0x09 + (ch))
|
||||
#define AD7606_CALIB_GAIN_MASK GENMASK(5, 0)
|
||||
#define AD7606_CALIB_OFFSET(ch) (0x11 + (ch))
|
||||
#define AD7606_CALIB_PHASE(ch) (0x19 + (ch))
|
||||
|
||||
struct ad7606_state;
|
||||
|
||||
typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev,
|
||||
@@ -61,6 +66,9 @@ typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
|
||||
* @init_delay_ms: required delay in milliseconds for initialization
|
||||
* after a restart
|
||||
* @offload_storagebits: storage bits used by the offload hw implementation
|
||||
* @calib_gain_avail: chip supports gain calibration
|
||||
* @calib_offset_avail: pointer to offset calibration range/limits array
|
||||
* @calib_phase_avail: pointer to phase calibration range/limits array
|
||||
*/
|
||||
struct ad7606_chip_info {
|
||||
unsigned int max_samplerate;
|
||||
@@ -74,22 +82,28 @@ struct ad7606_chip_info {
|
||||
bool os_req_reset;
|
||||
unsigned long init_delay_ms;
|
||||
u8 offload_storagebits;
|
||||
bool calib_gain_avail;
|
||||
const int *calib_offset_avail;
|
||||
const int (*calib_phase_avail)[2];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ad7606_chan_scale - channel scale configuration
|
||||
* struct ad7606_chan_info - channel configuration
|
||||
* @scale_avail: pointer to the array which stores the available scales
|
||||
* @num_scales: number of elements stored in the scale_avail array
|
||||
* @range: voltage range selection, selects which scale to apply
|
||||
* @reg_offset: offset for the register value, to be applied when
|
||||
* writing the value of 'range' to the register value
|
||||
* @r_gain: gain resistor value in ohms, to be set to match the
|
||||
* external r_filter value
|
||||
*/
|
||||
struct ad7606_chan_scale {
|
||||
struct ad7606_chan_info {
|
||||
#define AD760X_MAX_SCALES 16
|
||||
const unsigned int (*scale_avail)[2];
|
||||
unsigned int num_scales;
|
||||
unsigned int range;
|
||||
unsigned int reg_offset;
|
||||
unsigned int r_gain;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -97,7 +111,7 @@ struct ad7606_chan_scale {
|
||||
* @dev: pointer to kernel device
|
||||
* @chip_info: entry in the table of chips that describes this device
|
||||
* @bops: bus operations (SPI or parallel)
|
||||
* @chan_scales: scale configuration for channels
|
||||
* @chan_info: scale configuration for channels
|
||||
* @oversampling: oversampling selection
|
||||
* @cnvst_pwm: pointer to the PWM device connected to the cnvst pin
|
||||
* @base_address: address from where to read data in parallel operation
|
||||
@@ -128,7 +142,7 @@ struct ad7606_state {
|
||||
struct device *dev;
|
||||
const struct ad7606_chip_info *chip_info;
|
||||
const struct ad7606_bus_ops *bops;
|
||||
struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS];
|
||||
struct ad7606_chan_info chan_info[AD760X_MAX_CHANNELS];
|
||||
unsigned int oversampling;
|
||||
struct pwm_device *cnvst_pwm;
|
||||
void __iomem *base_address;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,24 +7,33 @@
|
||||
*/
|
||||
|
||||
#include <linux/align.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/find.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/adc/ad_sigma_delta.h>
|
||||
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/offload/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include <linux/iio/adc/ad_sigma_delta.h>
|
||||
#include <linux/iio/buffer-dmaengine.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define AD_SD_COMM_CHAN_MASK 0x3
|
||||
|
||||
@@ -40,7 +49,7 @@
|
||||
* @sigma_delta: The sigma delta device
|
||||
* @comm: New value for the communications register
|
||||
*/
|
||||
void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
|
||||
void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, u8 comm)
|
||||
{
|
||||
/* Some variants use the lower two bits of the communications register
|
||||
* to select the channel */
|
||||
@@ -61,7 +70,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, "IIO_AD_SIGMA_DELTA");
|
||||
int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
|
||||
unsigned int size, unsigned int val)
|
||||
{
|
||||
uint8_t *data = sigma_delta->tx_buf;
|
||||
u8 *data = sigma_delta->tx_buf;
|
||||
struct spi_transfer t = {
|
||||
.tx_buf = data,
|
||||
.len = size + 1,
|
||||
@@ -100,10 +109,18 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, "IIO_AD_SIGMA_DELTA");
|
||||
|
||||
static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
|
||||
unsigned int reg, unsigned int size, uint8_t *val)
|
||||
static void ad_sd_set_read_reg_addr(struct ad_sigma_delta *sigma_delta, u8 reg,
|
||||
u8 *data)
|
||||
{
|
||||
uint8_t *data = sigma_delta->tx_buf;
|
||||
data[0] = reg << sigma_delta->info->addr_shift;
|
||||
data[0] |= sigma_delta->info->read_mask;
|
||||
data[0] |= sigma_delta->comm;
|
||||
}
|
||||
|
||||
static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
|
||||
unsigned int reg, unsigned int size, u8 *val)
|
||||
{
|
||||
u8 *data = sigma_delta->tx_buf;
|
||||
int ret;
|
||||
struct spi_transfer t[] = {
|
||||
{
|
||||
@@ -120,9 +137,7 @@ static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
|
||||
spi_message_init(&m);
|
||||
|
||||
if (sigma_delta->info->has_registers) {
|
||||
data[0] = reg << sigma_delta->info->addr_shift;
|
||||
data[0] |= sigma_delta->info->read_mask;
|
||||
data[0] |= sigma_delta->comm;
|
||||
ad_sd_set_read_reg_addr(sigma_delta, reg, data);
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
}
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
@@ -187,11 +202,11 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, "IIO_AD_SIGMA_DELTA");
|
||||
int ad_sd_reset(struct ad_sigma_delta *sigma_delta)
|
||||
{
|
||||
unsigned int reset_length = sigma_delta->info->num_resetclks;
|
||||
uint8_t *buf;
|
||||
unsigned int size;
|
||||
u8 *buf;
|
||||
int ret;
|
||||
|
||||
size = DIV_ROUND_UP(reset_length, 8);
|
||||
size = BITS_TO_BYTES(reset_length);
|
||||
buf = kcalloc(size, sizeof(*buf), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
@@ -281,9 +296,7 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
|
||||
if (sigma_delta->info->has_registers) {
|
||||
unsigned int data_reg = sigma_delta->info->data_reg ?: AD_SD_REG_DATA;
|
||||
|
||||
data[0] = data_reg << sigma_delta->info->addr_shift;
|
||||
data[0] |= sigma_delta->info->read_mask;
|
||||
data[0] |= sigma_delta->comm;
|
||||
ad_sd_set_read_reg_addr(sigma_delta, data_reg, data);
|
||||
t[0].tx_buf = data;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
}
|
||||
@@ -420,7 +433,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
|
||||
data_reg = AD_SD_REG_DATA;
|
||||
|
||||
ret = ad_sd_read_reg(sigma_delta, data_reg,
|
||||
DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
|
||||
BITS_TO_BYTES(chan->scan_type.realbits + chan->scan_type.shift),
|
||||
&raw_sample);
|
||||
|
||||
out:
|
||||
@@ -454,9 +467,10 @@ EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, "IIO_AD_SIGMA_DELTA");
|
||||
static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
|
||||
unsigned int i, slot, samples_buf_size;
|
||||
unsigned int channel;
|
||||
uint8_t *samples_buf;
|
||||
const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type;
|
||||
struct spi_transfer *xfer = sigma_delta->sample_xfer;
|
||||
unsigned int i, slot, channel;
|
||||
u8 *samples_buf;
|
||||
int ret;
|
||||
|
||||
if (sigma_delta->num_slots == 1) {
|
||||
@@ -483,20 +497,55 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
||||
sigma_delta->active_slots = slot;
|
||||
sigma_delta->current_slot = 0;
|
||||
|
||||
if (sigma_delta->active_slots > 1) {
|
||||
ret = ad_sigma_delta_append_status(sigma_delta, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
|
||||
xfer[1].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
|
||||
xfer[1].bits_per_word = scan_type->realbits;
|
||||
xfer[1].len = spi_bpw_to_bytes(scan_type->realbits);
|
||||
} else {
|
||||
unsigned int samples_buf_size, scan_size;
|
||||
|
||||
if (sigma_delta->active_slots > 1) {
|
||||
ret = ad_sigma_delta_append_status(sigma_delta, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
samples_buf_size =
|
||||
ALIGN(slot * BITS_TO_BYTES(scan_type->storagebits),
|
||||
sizeof(s64));
|
||||
samples_buf_size += sizeof(s64);
|
||||
samples_buf = devm_krealloc(&sigma_delta->spi->dev,
|
||||
sigma_delta->samples_buf,
|
||||
samples_buf_size, GFP_KERNEL);
|
||||
if (!samples_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
sigma_delta->samples_buf = samples_buf;
|
||||
scan_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift);
|
||||
/* For 24-bit data, there is an extra byte of padding. */
|
||||
xfer[1].rx_buf = &sigma_delta->rx_buf[scan_size == 3 ? 1 : 0];
|
||||
xfer[1].len = scan_size + (sigma_delta->status_appended ? 1 : 0);
|
||||
}
|
||||
xfer[1].cs_change = 1;
|
||||
|
||||
if (sigma_delta->info->has_registers) {
|
||||
xfer[0].tx_buf = &sigma_delta->sample_addr;
|
||||
xfer[0].len = 1;
|
||||
|
||||
ad_sd_set_read_reg_addr(sigma_delta,
|
||||
sigma_delta->info->data_reg ?: AD_SD_REG_DATA,
|
||||
&sigma_delta->sample_addr);
|
||||
spi_message_init_with_transfers(&sigma_delta->sample_msg, xfer, 2);
|
||||
} else {
|
||||
spi_message_init_with_transfers(&sigma_delta->sample_msg,
|
||||
&xfer[1], 1);
|
||||
}
|
||||
|
||||
samples_buf_size = ALIGN(slot * indio_dev->channels[0].scan_type.storagebits, 8);
|
||||
samples_buf_size += sizeof(int64_t);
|
||||
samples_buf = devm_krealloc(&sigma_delta->spi->dev, sigma_delta->samples_buf,
|
||||
samples_buf_size, GFP_KERNEL);
|
||||
if (!samples_buf)
|
||||
return -ENOMEM;
|
||||
sigma_delta->sample_msg.offload = sigma_delta->offload;
|
||||
|
||||
sigma_delta->samples_buf = samples_buf;
|
||||
ret = spi_optimize_message(sigma_delta->spi, &sigma_delta->sample_msg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_bus_lock(sigma_delta->spi->controller);
|
||||
sigma_delta->bus_locked = true;
|
||||
@@ -510,24 +559,42 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
ad_sd_enable_irq(sigma_delta);
|
||||
if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
|
||||
struct spi_offload_trigger_config config = {
|
||||
.type = SPI_OFFLOAD_TRIGGER_DATA_READY,
|
||||
};
|
||||
|
||||
ret = spi_offload_trigger_enable(sigma_delta->offload,
|
||||
sigma_delta->offload_trigger,
|
||||
&config);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
} else {
|
||||
ad_sd_enable_irq(sigma_delta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unlock:
|
||||
spi_bus_unlock(sigma_delta->spi->controller);
|
||||
spi_unoptimize_message(&sigma_delta->sample_msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
static int ad_sd_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
|
||||
|
||||
reinit_completion(&sigma_delta->completion);
|
||||
wait_for_completion_timeout(&sigma_delta->completion, HZ);
|
||||
if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
|
||||
spi_offload_trigger_disable(sigma_delta->offload,
|
||||
sigma_delta->offload_trigger);
|
||||
} else {
|
||||
reinit_completion(&sigma_delta->completion);
|
||||
wait_for_completion_timeout(&sigma_delta->completion, HZ);
|
||||
|
||||
ad_sd_disable_irq(sigma_delta);
|
||||
ad_sd_disable_irq(sigma_delta);
|
||||
}
|
||||
|
||||
sigma_delta->keep_cs_asserted = false;
|
||||
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
|
||||
@@ -537,61 +604,32 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
|
||||
ad_sigma_delta_disable_all(sigma_delta);
|
||||
sigma_delta->bus_locked = false;
|
||||
return spi_bus_unlock(sigma_delta->spi->controller);
|
||||
spi_bus_unlock(sigma_delta->spi->controller);
|
||||
spi_unoptimize_message(&sigma_delta->sample_msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type;
|
||||
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
|
||||
uint8_t *data = sigma_delta->rx_buf;
|
||||
unsigned int transfer_size;
|
||||
u8 *data = sigma_delta->rx_buf;
|
||||
unsigned int sample_size;
|
||||
unsigned int sample_pos;
|
||||
unsigned int status_pos;
|
||||
unsigned int reg_size;
|
||||
unsigned int data_reg;
|
||||
int ret;
|
||||
|
||||
reg_size = indio_dev->channels[0].scan_type.realbits +
|
||||
indio_dev->channels[0].scan_type.shift;
|
||||
reg_size = DIV_ROUND_UP(reg_size, 8);
|
||||
reg_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift);
|
||||
/* For 24-bit data, there is an extra byte of padding. */
|
||||
status_pos = reg_size + (reg_size == 3 ? 1 : 0);
|
||||
|
||||
if (sigma_delta->info->data_reg != 0)
|
||||
data_reg = sigma_delta->info->data_reg;
|
||||
else
|
||||
data_reg = AD_SD_REG_DATA;
|
||||
|
||||
/* Status word will be appended to the sample during transfer */
|
||||
if (sigma_delta->status_appended)
|
||||
transfer_size = reg_size + 1;
|
||||
else
|
||||
transfer_size = reg_size;
|
||||
|
||||
switch (reg_size) {
|
||||
case 4:
|
||||
case 2:
|
||||
case 1:
|
||||
status_pos = reg_size;
|
||||
ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[0]);
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
* Data array after transfer will look like (if status is appended):
|
||||
* data[] = { [0][sample][sample][sample][status] }
|
||||
* Keeping the first byte 0 shifts the status position by 1 byte to the right.
|
||||
*/
|
||||
status_pos = reg_size + 1;
|
||||
|
||||
/* We store 24 bit samples in a 32 bit word. Keep the upper
|
||||
* byte set to zero. */
|
||||
ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err_ratelimited(&indio_dev->dev, "Unsupported reg_size: %u\n", reg_size);
|
||||
ret = spi_sync_locked(sigma_delta->spi, &sigma_delta->sample_msg);
|
||||
if (ret)
|
||||
goto irq_handled;
|
||||
}
|
||||
|
||||
/*
|
||||
* For devices sampling only one channel at
|
||||
@@ -617,7 +655,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
|
||||
}
|
||||
}
|
||||
|
||||
sample_size = indio_dev->channels[0].scan_type.storagebits / 8;
|
||||
sample_size = BITS_TO_BYTES(scan_type->storagebits);
|
||||
sample_pos = sample_size * sigma_delta->current_slot;
|
||||
memcpy(&sigma_delta->samples_buf[sample_pos], data, sample_size);
|
||||
sigma_delta->current_slot++;
|
||||
@@ -644,7 +682,7 @@ static bool ad_sd_validate_scan_mask(struct iio_dev *indio_dev, const unsigned l
|
||||
|
||||
static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
|
||||
.postenable = &ad_sd_buffer_postenable,
|
||||
.postdisable = &ad_sd_buffer_postdisable,
|
||||
.predisable = &ad_sd_buffer_predisable,
|
||||
.validate_scan_mask = &ad_sd_validate_scan_mask,
|
||||
};
|
||||
|
||||
@@ -671,7 +709,8 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
|
||||
if ((!sigma_delta->rdy_gpiod || gpiod_get_value(sigma_delta->rdy_gpiod)) &&
|
||||
ad_sd_disable_irq(sigma_delta)) {
|
||||
complete(&sigma_delta->completion);
|
||||
iio_trigger_poll(sigma_delta->trig);
|
||||
if (sigma_delta->trig)
|
||||
iio_trigger_poll(sigma_delta->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -704,17 +743,6 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
|
||||
unsigned long irq_flags = irq_get_trigger_type(sigma_delta->irq_line);
|
||||
int ret;
|
||||
|
||||
if (dev != &sigma_delta->spi->dev) {
|
||||
dev_err(dev, "Trigger parent should be '%s', got '%s'\n",
|
||||
dev_name(dev), dev_name(&sigma_delta->spi->dev));
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
sigma_delta->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (sigma_delta->trig == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
init_completion(&sigma_delta->completion);
|
||||
|
||||
sigma_delta->irq_dis = true;
|
||||
@@ -734,14 +762,33 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
|
||||
if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
|
||||
sigma_delta->offload_trigger =
|
||||
devm_spi_offload_trigger_get(dev, sigma_delta->offload,
|
||||
SPI_OFFLOAD_TRIGGER_DATA_READY);
|
||||
if (IS_ERR(sigma_delta->offload_trigger))
|
||||
return dev_err_probe(dev, PTR_ERR(sigma_delta->offload_trigger),
|
||||
"Failed to get SPI offload trigger\n");
|
||||
} else {
|
||||
if (dev != &sigma_delta->spi->dev)
|
||||
return dev_err_probe(dev, -EFAULT,
|
||||
"Trigger parent should be '%s', got '%s'\n",
|
||||
dev_name(dev), dev_name(&sigma_delta->spi->dev));
|
||||
|
||||
ret = devm_iio_trigger_register(dev, sigma_delta->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
sigma_delta->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name, iio_device_id(indio_dev));
|
||||
if (!sigma_delta->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
/* select default trigger */
|
||||
indio_dev->trig = iio_trigger_get(sigma_delta->trig);
|
||||
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
|
||||
|
||||
ret = devm_iio_trigger_register(dev, sigma_delta->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* select default trigger */
|
||||
indio_dev->trig = iio_trigger_get(sigma_delta->trig);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -761,12 +808,29 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi
|
||||
if (!sigma_delta->slots)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&ad_sd_trigger_handler,
|
||||
&ad_sd_buffer_setup_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
|
||||
struct dma_chan *rx_dma;
|
||||
|
||||
rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev,
|
||||
sigma_delta->offload);
|
||||
if (IS_ERR(rx_dma))
|
||||
return dev_err_probe(dev, PTR_ERR(rx_dma),
|
||||
"Failed to get RX DMA channel\n");
|
||||
|
||||
ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,
|
||||
rx_dma, IIO_BUFFER_DIRECTION_IN);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Cannot setup DMA buffer\n");
|
||||
|
||||
indio_dev->setup_ops = &ad_sd_buffer_setup_ops;
|
||||
} else {
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
&iio_pollfunc_store_time,
|
||||
&ad_sd_trigger_handler,
|
||||
&ad_sd_buffer_setup_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_ad_sd_probe_trigger(dev, indio_dev);
|
||||
}
|
||||
@@ -829,6 +893,20 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
|
||||
return sigma_delta->irq_line;
|
||||
}
|
||||
|
||||
if (info->supports_spi_offload) {
|
||||
struct spi_offload_config offload_config = {
|
||||
.capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
|
||||
SPI_OFFLOAD_CAP_RX_STREAM_DMA,
|
||||
};
|
||||
int ret;
|
||||
|
||||
sigma_delta->offload = devm_spi_offload_get(&spi->dev, spi,
|
||||
&offload_config);
|
||||
ret = PTR_ERR_OR_ZERO(sigma_delta->offload);
|
||||
if (ret && ret != -ENODEV)
|
||||
return dev_err_probe(&spi->dev, ret, "Failed to get SPI offload\n");
|
||||
}
|
||||
|
||||
iio_device_set_drvdata(indio_dev, sigma_delta);
|
||||
|
||||
return 0;
|
||||
@@ -838,3 +916,4 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_init, "IIO_AD_SIGMA_DELTA");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#define ADI_AXI_ADC_REG_CONFIG_CMOS_OR_LVDS_N BIT(7)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CTRL 0x0044
|
||||
#define ADI_AXI_ADC_CTRL_NUM_LANES_MSK GENMASK(12, 8)
|
||||
#define ADI_AXI_ADC_CTRL_SYNC_MSK BIT(3)
|
||||
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CNTRL_3 0x004c
|
||||
@@ -52,6 +54,10 @@
|
||||
#define AXI_AD485X_PACKET_FORMAT_20BIT 0x0
|
||||
#define AXI_AD485X_PACKET_FORMAT_24BIT 0x1
|
||||
#define AXI_AD485X_PACKET_FORMAT_32BIT 0x2
|
||||
#define AXI_AD408X_CNTRL_3_FILTER_EN_MSK BIT(0)
|
||||
|
||||
#define ADI_AXI_ADC_REG_SYNC_STATUS 0x0068
|
||||
#define ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK BIT(0)
|
||||
|
||||
#define ADI_AXI_ADC_REG_DRP_STATUS 0x0074
|
||||
#define ADI_AXI_ADC_DRP_LOCKED BIT(17)
|
||||
@@ -80,6 +86,9 @@
|
||||
#define ADI_AXI_ADC_REG_CHAN_CTRL_3(c) (0x0418 + (c) * 0x40)
|
||||
#define ADI_AXI_ADC_CHAN_PN_SEL_MASK GENMASK(19, 16)
|
||||
|
||||
#define ADI_AXI_ADC_REG_CHAN_USR_CTRL_2(c) (0x0424 + (c) * 0x40)
|
||||
#define ADI_AXI_ADC_CHAN_USR_CTRL_2_DEC_RATE_N_MASK GENMASK(15, 0)
|
||||
|
||||
/* IO Delays */
|
||||
#define ADI_AXI_ADC_REG_DELAY(l) (0x0800 + (l) * 0x4)
|
||||
#define AXI_ADC_DELAY_CTRL_MASK GENMASK(4, 0)
|
||||
@@ -242,6 +251,19 @@ static int axi_adc_test_pattern_set(struct iio_backend *back,
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_adc_oversampling_ratio_set(struct iio_backend *back,
|
||||
unsigned int chan,
|
||||
unsigned int rate)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
return regmap_update_bits(st->regmap,
|
||||
ADI_AXI_ADC_REG_CHAN_USR_CTRL_2(chan),
|
||||
ADI_AXI_ADC_CHAN_USR_CTRL_2_DEC_RATE_N_MASK,
|
||||
FIELD_PREP(ADI_AXI_ADC_CHAN_USR_CTRL_2_DEC_RATE_N_MASK,
|
||||
rate));
|
||||
}
|
||||
|
||||
static int axi_adc_read_chan_status(struct adi_axi_adc_state *st, unsigned int chan,
|
||||
unsigned int *status)
|
||||
{
|
||||
@@ -381,7 +403,8 @@ static int axi_adc_ad485x_data_size_set(struct iio_backend *back,
|
||||
}
|
||||
|
||||
static int axi_adc_ad485x_oversampling_ratio_set(struct iio_backend *back,
|
||||
unsigned int ratio)
|
||||
unsigned int chan,
|
||||
unsigned int ratio)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
@@ -402,6 +425,50 @@ static int axi_adc_ad485x_oversampling_ratio_set(struct iio_backend *back,
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_adc_ad408x_filter_type_set(struct iio_backend *back,
|
||||
enum iio_backend_filter_type type)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
if (type)
|
||||
return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
|
||||
AXI_AD408X_CNTRL_3_FILTER_EN_MSK);
|
||||
|
||||
return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
|
||||
AXI_AD408X_CNTRL_3_FILTER_EN_MSK);
|
||||
}
|
||||
|
||||
static int axi_adc_ad408x_interface_data_align(struct iio_backend *back,
|
||||
u32 timeout_us)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
|
||||
ADI_AXI_ADC_CTRL_SYNC_MSK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_read_poll_timeout(st->regmap, ADI_AXI_ADC_REG_SYNC_STATUS,
|
||||
val,
|
||||
FIELD_GET(ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK, val),
|
||||
1, timeout_us);
|
||||
}
|
||||
|
||||
static int axi_adc_num_lanes_set(struct iio_backend *back,
|
||||
unsigned int num_lanes)
|
||||
{
|
||||
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
|
||||
|
||||
if (!num_lanes)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
|
||||
ADI_AXI_ADC_CTRL_NUM_LANES_MSK,
|
||||
FIELD_PREP(ADI_AXI_ADC_CTRL_NUM_LANES_MSK, num_lanes));
|
||||
}
|
||||
|
||||
static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
@@ -549,6 +616,7 @@ static const struct iio_backend_ops adi_axi_adc_ops = {
|
||||
.test_pattern_set = axi_adc_test_pattern_set,
|
||||
.chan_status = axi_adc_chan_status,
|
||||
.interface_type_get = axi_adc_interface_type_get,
|
||||
.oversampling_ratio_set = axi_adc_oversampling_ratio_set,
|
||||
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
|
||||
.debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
|
||||
};
|
||||
@@ -582,6 +650,26 @@ static const struct iio_backend_info axi_ad485x = {
|
||||
.ops = &adi_ad485x_ops,
|
||||
};
|
||||
|
||||
static const struct iio_backend_ops adi_ad408x_ops = {
|
||||
.enable = axi_adc_enable,
|
||||
.disable = axi_adc_disable,
|
||||
.chan_enable = axi_adc_chan_enable,
|
||||
.chan_disable = axi_adc_chan_disable,
|
||||
.request_buffer = axi_adc_request_buffer,
|
||||
.free_buffer = axi_adc_free_buffer,
|
||||
.data_sample_trigger = axi_adc_data_sample_trigger,
|
||||
.filter_type_set = axi_adc_ad408x_filter_type_set,
|
||||
.interface_data_align = axi_adc_ad408x_interface_data_align,
|
||||
.num_lanes_set = axi_adc_num_lanes_set,
|
||||
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
|
||||
.debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
|
||||
};
|
||||
|
||||
static const struct iio_backend_info axi_ad408x = {
|
||||
.name = "axi-ad408x",
|
||||
.ops = &adi_ad408x_ops,
|
||||
};
|
||||
|
||||
static int adi_axi_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct adi_axi_adc_state *st;
|
||||
@@ -697,9 +785,15 @@ static const struct axi_adc_info adc_ad7606 = {
|
||||
.has_child_nodes = true,
|
||||
};
|
||||
|
||||
static const struct axi_adc_info adi_axi_ad408x = {
|
||||
.version = ADI_AXI_PCORE_VER(10, 0, 'a'),
|
||||
.backend_info = &axi_ad408x,
|
||||
};
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id adi_axi_adc_of_match[] = {
|
||||
{ .compatible = "adi,axi-adc-10.0.a", .data = &adc_generic },
|
||||
{ .compatible = "adi,axi-ad408x", .data = &adi_axi_ad408x },
|
||||
{ .compatible = "adi,axi-ad485x", .data = &adi_axi_ad485x },
|
||||
{ .compatible = "adi,axi-ad7606x", .data = &adc_ad7606 },
|
||||
{ }
|
||||
|
||||
@@ -1226,7 +1226,7 @@ static const struct at91_adc_trigger at91sam9260_triggers[] = {
|
||||
{ .name = "external", .value = 0xd, .is_external = true },
|
||||
};
|
||||
|
||||
static struct at91_adc_caps at91sam9260_caps = {
|
||||
static const struct at91_adc_caps at91sam9260_caps = {
|
||||
.calc_startup_ticks = calc_startup_ticks_9260,
|
||||
.num_channels = 4,
|
||||
.low_res_bits = 8,
|
||||
@@ -1250,7 +1250,7 @@ static const struct at91_adc_trigger at91sam9x5_triggers[] = {
|
||||
{ .name = "continuous", .value = 0x6 },
|
||||
};
|
||||
|
||||
static struct at91_adc_caps at91sam9rl_caps = {
|
||||
static const struct at91_adc_caps at91sam9rl_caps = {
|
||||
.has_ts = true,
|
||||
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
|
||||
.num_channels = 6,
|
||||
@@ -1268,7 +1268,7 @@ static struct at91_adc_caps at91sam9rl_caps = {
|
||||
.trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
|
||||
};
|
||||
|
||||
static struct at91_adc_caps at91sam9g45_caps = {
|
||||
static const struct at91_adc_caps at91sam9g45_caps = {
|
||||
.has_ts = true,
|
||||
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
|
||||
.num_channels = 8,
|
||||
@@ -1286,7 +1286,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
|
||||
.trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
|
||||
};
|
||||
|
||||
static struct at91_adc_caps at91sam9x5_caps = {
|
||||
static const struct at91_adc_caps at91sam9x5_caps = {
|
||||
.has_ts = true,
|
||||
.has_tsmr = true,
|
||||
.ts_filter_average = 3,
|
||||
@@ -1308,7 +1308,7 @@ static struct at91_adc_caps at91sam9x5_caps = {
|
||||
.trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
|
||||
};
|
||||
|
||||
static struct at91_adc_caps sama5d3_caps = {
|
||||
static const struct at91_adc_caps sama5d3_caps = {
|
||||
.has_ts = true,
|
||||
.has_tsmr = true,
|
||||
.ts_filter_average = 3,
|
||||
|
||||
@@ -173,7 +173,7 @@ static const struct iio_map axp22x_maps[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct iio_map axp717_maps[] = {
|
||||
static const struct iio_map axp717_maps[] = {
|
||||
{
|
||||
.consumer_dev_name = "axp20x-usb-power-supply",
|
||||
.consumer_channel = "vbus_v",
|
||||
|
||||
@@ -467,7 +467,7 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
|
||||
struct {
|
||||
__le16 values[DLN2_ADC_MAX_CHANNELS];
|
||||
aligned_s64 timestamp_space;
|
||||
} data;
|
||||
} data = { };
|
||||
struct dln2_adc_get_all_vals dev_data;
|
||||
struct dln2_adc *dln2 = iio_priv(indio_dev);
|
||||
const struct dln2_adc_demux_table *t;
|
||||
@@ -479,8 +479,6 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
/* Demux operation */
|
||||
for (i = 0; i < dln2->demux_count; ++i) {
|
||||
t = &dln2->demux[i];
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#define DRV_NAME "hi8435"
|
||||
|
||||
/* Register offsets for HI-8435 */
|
||||
#define HI8435_CTRL_REG 0x02
|
||||
#define HI8435_PSEN_REG 0x04
|
||||
@@ -536,7 +534,7 @@ MODULE_DEVICE_TABLE(spi, hi8435_id);
|
||||
|
||||
static struct spi_driver hi8435_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.name = "hi8435",
|
||||
.of_match_table = hi8435_dt_ids,
|
||||
},
|
||||
.probe = hi8435_probe,
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#define DRIVER_NAME "max9611"
|
||||
|
||||
/* max9611 register addresses */
|
||||
#define MAX9611_REG_CSA_DATA 0x00
|
||||
#define MAX9611_REG_RS_DATA 0x02
|
||||
@@ -553,7 +551,7 @@ static int max9611_probe(struct i2c_client *client)
|
||||
|
||||
static struct i2c_driver max9611_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.name = "max9611",
|
||||
.of_match_table = max9611_of_table,
|
||||
},
|
||||
.probe = max9611_probe,
|
||||
|
||||
@@ -44,7 +44,7 @@ struct mp2629_adc {
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static struct iio_chan_spec mp2629_channels[] = {
|
||||
static const struct iio_chan_spec mp2629_channels[] = {
|
||||
MP2629_ADC_CHAN(BATT_VOLT, IIO_VOLTAGE),
|
||||
MP2629_ADC_CHAN(SYSTEM_VOLT, IIO_VOLTAGE),
|
||||
MP2629_ADC_CHAN(INPUT_VOLT, IIO_VOLTAGE),
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -24,11 +25,11 @@
|
||||
#include <dt-bindings/iio/adc/mediatek,mt6357-auxadc.h>
|
||||
#include <dt-bindings/iio/adc/mediatek,mt6358-auxadc.h>
|
||||
#include <dt-bindings/iio/adc/mediatek,mt6359-auxadc.h>
|
||||
#include <dt-bindings/iio/adc/mediatek,mt6363-auxadc.h>
|
||||
|
||||
#define AUXADC_AVG_TIME_US 10
|
||||
#define AUXADC_POLL_DELAY_US 100
|
||||
#define AUXADC_TIMEOUT_US 32000
|
||||
#define AUXADC_VOLT_FULL 1800
|
||||
#define IMP_STOP_DELAY_US 150
|
||||
#define IMP_POLL_DELAY_US 1000
|
||||
|
||||
@@ -46,6 +47,12 @@
|
||||
#define MT6359_IMP0_CONV_EN BIT(0)
|
||||
#define MT6359_IMP1_IRQ_RDY BIT(15)
|
||||
|
||||
#define MT6363_EXT_CHAN_MASK GENMASK(2, 0)
|
||||
#define MT6363_EXT_PURES_MASK GENMASK(4, 3)
|
||||
#define MT6363_PULLUP_RES_100K 0
|
||||
#define MT6363_PULLUP_RES_30K 1
|
||||
#define MT6363_PULLUP_RES_OPEN 3
|
||||
|
||||
enum mtk_pmic_auxadc_regs {
|
||||
PMIC_AUXADC_ADC0,
|
||||
PMIC_AUXADC_DCM_CON,
|
||||
@@ -54,6 +61,8 @@ enum mtk_pmic_auxadc_regs {
|
||||
PMIC_AUXADC_IMP3,
|
||||
PMIC_AUXADC_RQST0,
|
||||
PMIC_AUXADC_RQST1,
|
||||
PMIC_AUXADC_RQST3,
|
||||
PMIC_AUXADC_SDMADC_CON0,
|
||||
PMIC_HK_TOP_WKEY,
|
||||
PMIC_HK_TOP_RST_CON0,
|
||||
PMIC_FGADC_R_CON0,
|
||||
@@ -75,7 +84,16 @@ enum mtk_pmic_auxadc_channels {
|
||||
PMIC_AUXADC_CHAN_TSX_TEMP,
|
||||
PMIC_AUXADC_CHAN_HPOFS_CAL,
|
||||
PMIC_AUXADC_CHAN_DCXO_TEMP,
|
||||
PMIC_AUXADC_CHAN_VTREF,
|
||||
PMIC_AUXADC_CHAN_VBIF,
|
||||
PMIC_AUXADC_CHAN_VSYSSNS,
|
||||
PMIC_AUXADC_CHAN_VIN1,
|
||||
PMIC_AUXADC_CHAN_VIN2,
|
||||
PMIC_AUXADC_CHAN_VIN3,
|
||||
PMIC_AUXADC_CHAN_VIN4,
|
||||
PMIC_AUXADC_CHAN_VIN5,
|
||||
PMIC_AUXADC_CHAN_VIN6,
|
||||
PMIC_AUXADC_CHAN_VIN7,
|
||||
PMIC_AUXADC_CHAN_IBAT,
|
||||
PMIC_AUXADC_CHAN_VBAT,
|
||||
PMIC_AUXADC_CHAN_MAX
|
||||
@@ -101,12 +119,22 @@ struct mt6359_auxadc {
|
||||
* struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data
|
||||
* @req_idx: Request register number
|
||||
* @req_mask: Bitmask to activate a channel
|
||||
* @rdy_idx: Readiness register number
|
||||
* @rdy_mask: Bitmask to determine channel readiness
|
||||
* @ext_sel_idx: PMIC GPIO channel register number
|
||||
* @ext_sel_ch: PMIC GPIO number
|
||||
* @ext_sel_pu: PMIC GPIO channel pullup resistor selector
|
||||
* @num_samples: Number of AUXADC samples for averaging
|
||||
* @r_ratio: Resistance ratio fractional
|
||||
*/
|
||||
struct mtk_pmic_auxadc_chan {
|
||||
u8 req_idx;
|
||||
u16 req_mask;
|
||||
u8 rdy_idx;
|
||||
u16 rdy_mask;
|
||||
s8 ext_sel_idx;
|
||||
u8 ext_sel_ch;
|
||||
u8 ext_sel_pu;
|
||||
u16 num_samples;
|
||||
struct u8_fract r_ratio;
|
||||
};
|
||||
@@ -119,7 +147,10 @@ struct mtk_pmic_auxadc_chan {
|
||||
* @desc: PMIC AUXADC channel data
|
||||
* @regs: List of PMIC specific registers
|
||||
* @sec_unlock_key: Security unlock key for HK_TOP writes
|
||||
* @vref_mV: AUXADC Reference Voltage (VREF) in millivolts
|
||||
* @imp_adc_num: ADC channel for battery impedance readings
|
||||
* @is_spmi: Defines whether this PMIC communicates over SPMI
|
||||
* @no_reset: If true, this PMIC does not support ADC reset
|
||||
* @read_imp: Callback to read impedance channels
|
||||
*/
|
||||
struct mtk_pmic_auxadc_info {
|
||||
@@ -129,18 +160,34 @@ struct mtk_pmic_auxadc_info {
|
||||
const struct mtk_pmic_auxadc_chan *desc;
|
||||
const u16 *regs;
|
||||
u16 sec_unlock_key;
|
||||
u32 vref_mV;
|
||||
u8 imp_adc_num;
|
||||
int (*read_imp)(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat);
|
||||
bool is_spmi;
|
||||
bool no_reset;
|
||||
int (*read_imp)(struct mt6359_auxadc *adc_dev,
|
||||
const struct iio_chan_spec *chan, int *vbat, int *ibat);
|
||||
};
|
||||
|
||||
#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _samples, _rnum, _rdiv) \
|
||||
#define MTK_PMIC_ADC_EXT_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit, \
|
||||
_ext_sel_idx, _ext_sel_ch, _ext_sel_pu, \
|
||||
_samples, _rnum, _rdiv) \
|
||||
[PMIC_AUXADC_CHAN_##_ch_idx] = { \
|
||||
.req_idx = _req_idx, \
|
||||
.req_mask = BIT(_req_bit), \
|
||||
.rdy_idx = _rdy_idx, \
|
||||
.rdy_mask = BIT(_rdy_bit), \
|
||||
.ext_sel_idx = _ext_sel_idx, \
|
||||
.ext_sel_ch = _ext_sel_ch, \
|
||||
.ext_sel_pu = _ext_sel_pu, \
|
||||
.num_samples = _samples, \
|
||||
.r_ratio = { _rnum, _rdiv } \
|
||||
}
|
||||
|
||||
#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit, \
|
||||
_samples, _rnum, _rdiv) \
|
||||
MTK_PMIC_ADC_EXT_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit, \
|
||||
-1, 0, 0, _samples, _rnum, _rdiv)
|
||||
|
||||
#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type) \
|
||||
{ \
|
||||
.type = _ch_type, \
|
||||
@@ -177,21 +224,21 @@ static const struct iio_chan_spec mt6357_auxadc_channels[] = {
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = {
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP0, 8, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP0, 8, 256, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP0, 8, 16, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
|
||||
/* Battery impedance channels */
|
||||
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
|
||||
};
|
||||
|
||||
static const u16 mt6357_auxadc_regs[] = {
|
||||
@@ -224,22 +271,22 @@ static const struct iio_chan_spec mt6358_auxadc_channels[] = {
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = {
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 2, 1),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 2, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP0, 8, 8, 2, 1),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP0, 8, 8, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP0, 8, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP0, 8, 256, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP0, 8, 16, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP0, 8, 8, 2, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
|
||||
|
||||
/* Battery impedance channels */
|
||||
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP0, 8, 128, 7, 2),
|
||||
};
|
||||
|
||||
static const u16 mt6358_auxadc_regs[] = {
|
||||
@@ -272,22 +319,22 @@ static const struct iio_chan_spec mt6359_auxadc_channels[] = {
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 5, 2),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 5, 2),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15 ,8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP1, 15, 8, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP1, 15, 128, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP1, 15, 256, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP1, 15, 16, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
|
||||
|
||||
/* Battery impedance channels */
|
||||
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(IBAT, 0, 0, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
|
||||
MTK_PMIC_ADC_CHAN(IBAT, 0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
|
||||
};
|
||||
|
||||
static const u16 mt6359_auxadc_regs[] = {
|
||||
@@ -302,6 +349,107 @@ static const u16 mt6359_auxadc_regs[] = {
|
||||
[PMIC_AUXADC_IMP3] = 0x120e,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mt6363_auxadc_channels[] = {
|
||||
MTK_PMIC_IIO_CHAN(MT6363, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, cdt_v, VCDT, 2, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, sys_sns_v, VSYSSNS, 6, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, tref_v, VTREF, 11, 12, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),
|
||||
|
||||
/* For VIN, ADC12 holds the result depending on which GPIO was activated */
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in1_v, VIN1, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in2_v, VIN2, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in3_v, VIN3, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in4_v, VIN4, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in5_v, VIN5, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in6_v, VIN6, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in7_v, VIN7, 45, 15, IIO_VOLTAGE),
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_chan mt6363_auxadc_ch_desc[] = {
|
||||
MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_ADC0, 15, 64, 4, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_ADC0, 15, 32, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VSYSSNS, PMIC_AUXADC_RQST1, 6, PMIC_AUXADC_ADC0, 15, 64, 3, 1),
|
||||
MTK_PMIC_ADC_CHAN(VTREF, PMIC_AUXADC_RQST1, 3, PMIC_AUXADC_ADC0, 15, 32, 3, 2),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST3, 0, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST3, 1, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST3, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN1,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 1, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN2,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 2, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN3,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 3, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN4,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 4, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN5,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 5, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN6,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 6, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN7,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 7, MT6363_PULLUP_RES_100K, 32, 1, 1),
|
||||
};
|
||||
|
||||
static const u16 mt6363_auxadc_regs[] = {
|
||||
[PMIC_AUXADC_RQST0] = 0x1108,
|
||||
[PMIC_AUXADC_RQST1] = 0x1109,
|
||||
[PMIC_AUXADC_RQST3] = 0x110c,
|
||||
[PMIC_AUXADC_ADC0] = 0x1088,
|
||||
[PMIC_AUXADC_IMP0] = 0x1208,
|
||||
[PMIC_AUXADC_IMP1] = 0x1209,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mt6373_auxadc_channels[] = {
|
||||
MTK_PMIC_IIO_CHAN(MT6363, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),
|
||||
|
||||
/* For VIN, ADC12 holds the result depending on which GPIO was activated */
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in1_v, VIN1, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in2_v, VIN2, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in3_v, VIN3, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in4_v, VIN4, 45, 15, IIO_VOLTAGE),
|
||||
MTK_PMIC_IIO_CHAN(MT6363, in5_v, VIN5, 45, 15, IIO_VOLTAGE),
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_chan mt6373_auxadc_ch_desc[] = {
|
||||
MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST3, 0, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST3, 1, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST3, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
|
||||
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN1,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 1, MT6363_PULLUP_RES_30K, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN2,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 2, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN3,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 3, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN4,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 4, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
|
||||
MTK_PMIC_ADC_EXT_CHAN(VIN5,
|
||||
PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
|
||||
PMIC_AUXADC_SDMADC_CON0, 5, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
|
||||
};
|
||||
|
||||
static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
@@ -313,9 +461,10 @@ static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
|
||||
regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
|
||||
}
|
||||
|
||||
static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
|
||||
static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev, const struct iio_chan_spec *chan)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
|
||||
struct regmap *regmap = adc_dev->regmap;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -323,8 +472,8 @@ static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
|
||||
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
|
||||
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
|
||||
|
||||
ret = regmap_read_poll_timeout(adc_dev->regmap, cinfo->regs[PMIC_AUXADC_IMP0],
|
||||
val, val & MT6358_IMP0_IRQ_RDY,
|
||||
ret = regmap_read_poll_timeout(regmap, cinfo->regs[desc->rdy_idx],
|
||||
val, val & desc->rdy_mask,
|
||||
IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
|
||||
if (ret) {
|
||||
mt6358_stop_imp_conv(adc_dev);
|
||||
@@ -334,7 +483,8 @@ static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
|
||||
static int mt6358_read_imp(struct mt6359_auxadc *adc_dev,
|
||||
const struct iio_chan_spec *chan, int *vbat, int *ibat)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
struct regmap *regmap = adc_dev->regmap;
|
||||
@@ -342,7 +492,7 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
|
||||
u32 val_v;
|
||||
int ret;
|
||||
|
||||
ret = mt6358_start_imp_conv(adc_dev);
|
||||
ret = mt6358_start_imp_conv(adc_dev, chan);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -359,17 +509,19 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt6359_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
|
||||
static int mt6359_read_imp(struct mt6359_auxadc *adc_dev,
|
||||
const struct iio_chan_spec *chan, int *vbat, int *ibat)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
|
||||
struct regmap *regmap = adc_dev->regmap;
|
||||
u32 val, val_v, val_i;
|
||||
int ret;
|
||||
|
||||
/* Start conversion */
|
||||
regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN);
|
||||
ret = regmap_read_poll_timeout(regmap, cinfo->regs[PMIC_AUXADC_IMP1],
|
||||
val, val & MT6359_IMP1_IRQ_RDY,
|
||||
ret = regmap_read_poll_timeout(regmap, cinfo->regs[desc->rdy_idx],
|
||||
val, val & desc->rdy_mask,
|
||||
IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
|
||||
|
||||
/* Stop conversion regardless of the result */
|
||||
@@ -404,6 +556,7 @@ static const struct mtk_pmic_auxadc_info mt6357_chip_info = {
|
||||
.regs = mt6357_auxadc_regs,
|
||||
.imp_adc_num = MT6357_IMP_ADC_NUM,
|
||||
.read_imp = mt6358_read_imp,
|
||||
.vref_mV = 1800,
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
|
||||
@@ -414,6 +567,7 @@ static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
|
||||
.regs = mt6358_auxadc_regs,
|
||||
.imp_adc_num = MT6358_IMP_ADC_NUM,
|
||||
.read_imp = mt6358_read_imp,
|
||||
.vref_mV = 1800,
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
|
||||
@@ -424,6 +578,29 @@ static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
|
||||
.regs = mt6359_auxadc_regs,
|
||||
.sec_unlock_key = 0x6359,
|
||||
.read_imp = mt6359_read_imp,
|
||||
.vref_mV = 1800,
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_info mt6363_chip_info = {
|
||||
.model_name = "MT6363",
|
||||
.channels = mt6363_auxadc_channels,
|
||||
.num_channels = ARRAY_SIZE(mt6363_auxadc_channels),
|
||||
.desc = mt6363_auxadc_ch_desc,
|
||||
.regs = mt6363_auxadc_regs,
|
||||
.is_spmi = true,
|
||||
.no_reset = true,
|
||||
.vref_mV = 1840,
|
||||
};
|
||||
|
||||
static const struct mtk_pmic_auxadc_info mt6373_chip_info = {
|
||||
.model_name = "MT6373",
|
||||
.channels = mt6373_auxadc_channels,
|
||||
.num_channels = ARRAY_SIZE(mt6373_auxadc_channels),
|
||||
.desc = mt6373_auxadc_ch_desc,
|
||||
.regs = mt6363_auxadc_regs,
|
||||
.is_spmi = true,
|
||||
.no_reset = true,
|
||||
.vref_mV = 1840,
|
||||
};
|
||||
|
||||
static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
|
||||
@@ -431,6 +608,10 @@ static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
struct regmap *regmap = adc_dev->regmap;
|
||||
|
||||
/* Some PMICs do not support reset */
|
||||
if (cinfo->no_reset)
|
||||
return;
|
||||
|
||||
/* Unlock HK_TOP writes */
|
||||
if (cinfo->sec_unlock_key)
|
||||
regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key);
|
||||
@@ -446,13 +627,29 @@ static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
|
||||
regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0);
|
||||
}
|
||||
|
||||
static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
|
||||
const struct iio_chan_spec *chan, int *out)
|
||||
/**
|
||||
* mt6359_auxadc_sample_adc_val() - Start ADC channel sampling and read value
|
||||
* @adc_dev: Main driver structure
|
||||
* @chan: IIO Channel spec for requested ADC
|
||||
* @out: Preallocated variable to store the value read from HW
|
||||
*
|
||||
* This function starts the sampling for an ADC channel, waits until all
|
||||
* of the samples are averaged and then reads the value from the HW.
|
||||
*
|
||||
* Note that the caller must stop the ADC sampling on its own, as this
|
||||
* function *never* stops it.
|
||||
*
|
||||
* Return:
|
||||
* Negative number for error;
|
||||
* Upon success returns zero and writes the read value to *out.
|
||||
*/
|
||||
static int mt6359_auxadc_sample_adc_val(struct mt6359_auxadc *adc_dev,
|
||||
const struct iio_chan_spec *chan, u32 *out)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
|
||||
struct regmap *regmap = adc_dev->regmap;
|
||||
u32 val;
|
||||
u32 reg, rdy_mask, val, lval;
|
||||
int ret;
|
||||
|
||||
/* Request to start sampling for ADC channel */
|
||||
@@ -463,16 +660,95 @@ static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
|
||||
/* Wait until all samples are averaged */
|
||||
fsleep(desc->num_samples * AUXADC_AVG_TIME_US);
|
||||
|
||||
ret = regmap_read_poll_timeout(regmap,
|
||||
cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1),
|
||||
val, val & PMIC_AUXADC_RDY_BIT,
|
||||
reg = cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1);
|
||||
rdy_mask = PMIC_AUXADC_RDY_BIT;
|
||||
|
||||
/*
|
||||
* Even though for both PWRAP and SPMI cases the ADC HW signals that
|
||||
* the data is ready by setting AUXADC_RDY_BIT, for SPMI the register
|
||||
* read is only 8 bits long: for this case, the check has to be done
|
||||
* on the ADC(x)_H register (high bits) and the rdy_mask needs to be
|
||||
* shifted to the right by the same 8 bits.
|
||||
*/
|
||||
if (cinfo->is_spmi) {
|
||||
rdy_mask >>= 8;
|
||||
reg += 1;
|
||||
}
|
||||
|
||||
ret = regmap_read_poll_timeout(regmap, reg, val, val & rdy_mask,
|
||||
AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_dbg(adc_dev->dev, "ADC read timeout for chan %lu\n", chan->address);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cinfo->is_spmi) {
|
||||
ret = regmap_read(regmap, reg - 1, &lval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = (val << 8) | lval;
|
||||
}
|
||||
|
||||
*out = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
|
||||
const struct iio_chan_spec *chan, int *out)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
|
||||
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
|
||||
struct regmap *regmap = adc_dev->regmap;
|
||||
int ret, adc_stop_err;
|
||||
u8 ext_sel;
|
||||
u32 val;
|
||||
|
||||
if (desc->ext_sel_idx >= 0) {
|
||||
ext_sel = FIELD_PREP(MT6363_EXT_PURES_MASK, desc->ext_sel_pu);
|
||||
ext_sel |= FIELD_PREP(MT6363_EXT_CHAN_MASK, desc->ext_sel_ch);
|
||||
|
||||
ret = regmap_update_bits(regmap, cinfo->regs[desc->ext_sel_idx],
|
||||
MT6363_EXT_PURES_MASK | MT6363_EXT_CHAN_MASK,
|
||||
ext_sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get sampled value, then stop sampling unconditionally; the gathered
|
||||
* value is good regardless of if the ADC could be stopped.
|
||||
*
|
||||
* Note that if the ADC cannot be stopped but sampling was ok, this
|
||||
* function will not return any error, but will set the timed_out
|
||||
* status: this is not critical, as the ADC may auto recover and auto
|
||||
* stop after some time (depending on the PMIC model); if not, the next
|
||||
* read attempt will return -ETIMEDOUT and, for models that support it,
|
||||
* reset will be triggered.
|
||||
*/
|
||||
ret = mt6359_auxadc_sample_adc_val(adc_dev, chan, &val);
|
||||
|
||||
adc_stop_err = regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
|
||||
if (adc_stop_err) {
|
||||
dev_warn(adc_dev->dev, "Could not stop the ADC: %d\n,", adc_stop_err);
|
||||
adc_dev->timed_out = true;
|
||||
}
|
||||
|
||||
/* If any sampling error occurred, the retrieved value is invalid */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Stop sampling */
|
||||
regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
|
||||
/* ...and deactivate the ADC GPIO if previously done */
|
||||
if (desc->ext_sel_idx >= 0) {
|
||||
ext_sel = FIELD_PREP(MT6363_EXT_PURES_MASK, MT6363_PULLUP_RES_OPEN);
|
||||
|
||||
ret = regmap_update_bits(regmap, cinfo->regs[desc->ext_sel_idx],
|
||||
MT6363_EXT_PURES_MASK, ext_sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Everything went fine, give back the ADC reading */
|
||||
*out = val & GENMASK(chan->scan_type.realbits - 1, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -493,7 +769,7 @@ static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
|
||||
int ret;
|
||||
|
||||
if (mask == IIO_CHAN_INFO_SCALE) {
|
||||
*val = desc->r_ratio.numerator * AUXADC_VOLT_FULL;
|
||||
*val = desc->r_ratio.numerator * cinfo->vref_mV;
|
||||
|
||||
if (desc->r_ratio.denominator > 1) {
|
||||
*val2 = desc->r_ratio.denominator;
|
||||
@@ -506,10 +782,16 @@ static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
|
||||
scoped_guard(mutex, &adc_dev->lock) {
|
||||
switch (chan->scan_index) {
|
||||
case PMIC_AUXADC_CHAN_IBAT:
|
||||
ret = adc_dev->chip_info->read_imp(adc_dev, NULL, val);
|
||||
if (!adc_dev->chip_info->read_imp)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = adc_dev->chip_info->read_imp(adc_dev, chan, NULL, val);
|
||||
break;
|
||||
case PMIC_AUXADC_CHAN_VBAT:
|
||||
ret = adc_dev->chip_info->read_imp(adc_dev, val, NULL);
|
||||
if (!adc_dev->chip_info->read_imp)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = adc_dev->chip_info->read_imp(adc_dev, chan, val, NULL);
|
||||
break;
|
||||
default:
|
||||
ret = mt6359_auxadc_read_adc(adc_dev, chan, val);
|
||||
@@ -543,15 +825,36 @@ static const struct iio_info mt6359_auxadc_iio_info = {
|
||||
|
||||
static int mt6359_auxadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct mtk_pmic_auxadc_info *chip_info;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *mt6397_mfd_dev = dev->parent;
|
||||
struct device *mfd_dev = dev->parent;
|
||||
struct mt6359_auxadc *adc_dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct device *regmap_dev;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
chip_info = device_get_match_data(dev);
|
||||
if (!chip_info)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* The regmap for this device has to be acquired differently for
|
||||
* SoC PMIC Wrapper and SPMI PMIC cases:
|
||||
*
|
||||
* If this is under SPMI, the regmap comes from the direct parent of
|
||||
* this driver: this_device->parent(mfd).
|
||||
* ... or ...
|
||||
* If this is under the SoC PMIC Wrapper, the regmap comes from the
|
||||
* parent of the MT6397 MFD: this_device->parent(mfd)->parent(pwrap)
|
||||
*/
|
||||
if (chip_info->is_spmi)
|
||||
regmap_dev = mfd_dev;
|
||||
else
|
||||
regmap_dev = mfd_dev->parent;
|
||||
|
||||
|
||||
/* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */
|
||||
regmap = dev_get_regmap(mt6397_mfd_dev->parent, NULL);
|
||||
regmap = dev_get_regmap(regmap_dev, NULL);
|
||||
if (!regmap)
|
||||
return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
|
||||
|
||||
@@ -562,10 +865,7 @@ static int mt6359_auxadc_probe(struct platform_device *pdev)
|
||||
adc_dev = iio_priv(indio_dev);
|
||||
adc_dev->regmap = regmap;
|
||||
adc_dev->dev = dev;
|
||||
|
||||
adc_dev->chip_info = device_get_match_data(dev);
|
||||
if (!adc_dev->chip_info)
|
||||
return -EINVAL;
|
||||
adc_dev->chip_info = chip_info;
|
||||
|
||||
mutex_init(&adc_dev->lock);
|
||||
|
||||
@@ -588,6 +888,8 @@ static const struct of_device_id mt6359_auxadc_of_match[] = {
|
||||
{ .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info },
|
||||
{ .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info },
|
||||
{ .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info },
|
||||
{ .compatible = "mediatek,mt6363-auxadc", .data = &mt6363_chip_info },
|
||||
{ .compatible = "mediatek,mt6373-auxadc", .data = &mt6373_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match);
|
||||
|
||||
@@ -264,10 +264,9 @@ static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
u16 values[MT6360_CHAN_MAX];
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
} data = { };
|
||||
int i = 0, bit, val, ret;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
ret = mt6360_adc_read_channel(mad, bit, &val);
|
||||
if (ret < 0) {
|
||||
|
||||
@@ -330,7 +330,7 @@ static int qcom_vadc7_scale_hw_calib_die_temp(
|
||||
const struct adc5_data *data,
|
||||
u16 adc_code, int *result_mdec);
|
||||
|
||||
static struct qcom_adc5_scale_type scale_adc5_fn[] = {
|
||||
static const struct qcom_adc5_scale_type scale_adc5_fn[] = {
|
||||
[SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
|
||||
[SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
|
||||
[SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
|
||||
|
||||
@@ -404,12 +404,10 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
u16 values[SARADC_MAX_CHANNELS];
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
} data = { };
|
||||
int ret;
|
||||
int i, j = 0;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
|
||||
iio_for_each_active_channel(i_dev, i) {
|
||||
|
||||
@@ -645,12 +645,10 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
u16 vals[RTQ6056_MAX_CHANNEL];
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
} data = { };
|
||||
unsigned int raw;
|
||||
int i = 0, bit, ret;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
iio_for_each_active_channel(indio_dev, bit) {
|
||||
|
||||
@@ -407,7 +407,6 @@ static const struct irq_domain_ops stm32_adc_domain_ops = {
|
||||
static int stm32_adc_irq_probe(struct platform_device *pdev,
|
||||
struct stm32_adc_priv *priv)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
@@ -421,7 +420,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
|
||||
return priv->irq[i];
|
||||
}
|
||||
|
||||
priv->domain = irq_domain_create_simple(of_fwnode_handle(np),
|
||||
priv->domain = irq_domain_create_simple(dev_fwnode(&pdev->dev),
|
||||
STM32_ADC_MAX_ADCS, 0,
|
||||
&stm32_adc_domain_ops,
|
||||
priv);
|
||||
|
||||
@@ -216,7 +216,7 @@ struct stm32_adc;
|
||||
struct stm32_adc_cfg {
|
||||
const struct stm32_adc_regspec *regs;
|
||||
const struct stm32_adc_info *adc_info;
|
||||
struct stm32_adc_trig_info *trigs;
|
||||
const struct stm32_adc_trig_info *trigs;
|
||||
bool clk_required;
|
||||
bool has_vregready;
|
||||
bool has_boostmode;
|
||||
@@ -383,7 +383,7 @@ static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = {
|
||||
};
|
||||
|
||||
/* STM32F4 external trigger sources for all instances */
|
||||
static struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
|
||||
static const struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
|
||||
{ TIM1_CH1, STM32_EXT0 },
|
||||
{ TIM1_CH2, STM32_EXT1 },
|
||||
{ TIM1_CH3, STM32_EXT2 },
|
||||
@@ -473,7 +473,7 @@ static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = {
|
||||
};
|
||||
|
||||
/* STM32H7 external trigger sources for all instances */
|
||||
static struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
|
||||
static const struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
|
||||
{ TIM1_CH1, STM32_EXT0 },
|
||||
{ TIM1_CH2, STM32_EXT1 },
|
||||
{ TIM1_CH3, STM32_EXT2 },
|
||||
@@ -2470,7 +2470,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
|
||||
{
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
struct dma_slave_config config;
|
||||
struct dma_slave_config config = { };
|
||||
int ret;
|
||||
|
||||
adc->dma_chan = dma_request_chan(dev, "rx");
|
||||
@@ -2494,7 +2494,6 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
|
||||
}
|
||||
|
||||
/* Configure DMA channel to read data register */
|
||||
memset(&config, 0, sizeof(config));
|
||||
config.src_addr = (dma_addr_t)adc->common->phys_base;
|
||||
config.src_addr += adc->offset + adc->cfg->regs->dr;
|
||||
config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/iio/adc/stm32-dfsdm-adc.h>
|
||||
#include <linux/iio/backend.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
@@ -450,11 +450,9 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
s16 chan;
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
} scan = { };
|
||||
int chan, ret, res;
|
||||
|
||||
memset(&scan, 0, sizeof(scan));
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
chan = find_first_bit(indio_dev->active_scan_mask,
|
||||
iio_get_masklength(indio_dev));
|
||||
|
||||
@@ -507,12 +507,10 @@ static irqreturn_t ads1119_trigger_handler(int irq, void *private)
|
||||
struct {
|
||||
s16 sample;
|
||||
aligned_s64 timestamp;
|
||||
} scan;
|
||||
} scan = { };
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
||||
memset(&scan, 0, sizeof(scan));
|
||||
|
||||
if (!iio_trigger_using_own(indio_dev)) {
|
||||
index = find_first_bit(indio_dev->active_scan_mask,
|
||||
iio_get_masklength(indio_dev));
|
||||
|
||||
@@ -625,7 +625,7 @@ static irqreturn_t ads131e08_trigger_handler(int irq, void *private)
|
||||
* 16 bits of data into the buffer.
|
||||
*/
|
||||
unsigned int num_bytes = ADS131E08_NUM_DATA_BYTES(st->data_rate);
|
||||
u8 tweek_offset = num_bytes == 2 ? 1 : 0;
|
||||
u8 tweak_offset = num_bytes == 2 ? 1 : 0;
|
||||
|
||||
if (iio_trigger_using_own(indio_dev))
|
||||
ret = ads131e08_read_data(st, st->readback_len);
|
||||
@@ -640,25 +640,25 @@ static irqreturn_t ads131e08_trigger_handler(int irq, void *private)
|
||||
dest = st->tmp_buf.data + i * ADS131E08_NUM_STORAGE_BYTES;
|
||||
|
||||
/*
|
||||
* Tweek offset is 0:
|
||||
* Tweak offset is 0:
|
||||
* +---+---+---+---+
|
||||
* |D0 |D1 |D2 | X | (3 data bytes)
|
||||
* +---+---+---+---+
|
||||
* a+0 a+1 a+2 a+3
|
||||
*
|
||||
* Tweek offset is 1:
|
||||
* Tweak offset is 1:
|
||||
* +---+---+---+---+
|
||||
* |P0 |D0 |D1 | X | (one padding byte and 2 data bytes)
|
||||
* +---+---+---+---+
|
||||
* a+0 a+1 a+2 a+3
|
||||
*/
|
||||
memcpy(dest + tweek_offset, src, num_bytes);
|
||||
memcpy(dest + tweak_offset, src, num_bytes);
|
||||
|
||||
/*
|
||||
* Data conversion from 16 bits of data to 24 bits of data
|
||||
* is done by sign extension (properly filling padding byte).
|
||||
*/
|
||||
if (tweek_offset)
|
||||
if (tweak_offset)
|
||||
*dest = *src & BIT(7) ? 0xff : 0x00;
|
||||
|
||||
i++;
|
||||
|
||||
@@ -200,11 +200,9 @@ static irqreturn_t lmp92064_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
u16 values[2];
|
||||
aligned_s64 timestamp;
|
||||
} data;
|
||||
} data = { };
|
||||
int ret;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
ret = lmp92064_read_meas(priv, data.values);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@@ -276,7 +276,7 @@ static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
|
||||
struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx];
|
||||
unsigned int val, val_normalized = 0;
|
||||
int ret, i, count_skip = 0, max_count;
|
||||
struct spi_transfer xfer;
|
||||
struct spi_transfer xfer = { };
|
||||
struct spi_message msg;
|
||||
u8 cmd;
|
||||
|
||||
@@ -314,7 +314,6 @@ static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
|
||||
/* automatically power down on last sample */
|
||||
tx_buf[i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
|
||||
|
||||
memset(&xfer, 0, sizeof(xfer));
|
||||
xfer.tx_buf = tx_buf;
|
||||
xfer.rx_buf = rx_buf;
|
||||
xfer.len = sizeof(*tx_buf) * max_count;
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
/* This will be the driver name the kernel reports */
|
||||
#define DRIVER_NAME "vf610-adc"
|
||||
|
||||
/* Vybrid/IMX ADC registers */
|
||||
#define VF610_REG_ADC_HC0 0x00
|
||||
#define VF610_REG_ADC_HC1 0x04
|
||||
@@ -952,7 +949,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
|
||||
static struct platform_driver vf610_adc_driver = {
|
||||
.probe = vf610_adc_probe,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.name = "vf610-adc",
|
||||
.of_match_table = vf610_adc_match,
|
||||
.pm = pm_sleep_ptr(&vf610_adc_pm_ops),
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@ struct ad8366_state {
|
||||
struct gpio_desc *reset_gpio;
|
||||
unsigned char ch[2];
|
||||
enum ad8366_type type;
|
||||
struct ad8366_info *info;
|
||||
const struct ad8366_info *info;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) may require the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
@@ -53,7 +53,7 @@ struct ad8366_state {
|
||||
unsigned char data[2] __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
static struct ad8366_info ad8366_infos[] = {
|
||||
static const struct ad8366_info ad8366_infos[] = {
|
||||
[ID_AD8366] = {
|
||||
.gain_min = 4500,
|
||||
.gain_max = 20500,
|
||||
@@ -163,7 +163,7 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
|
||||
long mask)
|
||||
{
|
||||
struct ad8366_state *st = iio_priv(indio_dev);
|
||||
struct ad8366_info *inf = st->info;
|
||||
const struct ad8366_info *inf = st->info;
|
||||
int code = 0, gain;
|
||||
int ret;
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
/* ADA4250 Register Map */
|
||||
#define ADA4250_REG_GAIN_MUX 0x00
|
||||
@@ -56,13 +56,14 @@ enum ada4250_current_bias {
|
||||
struct ada4250_state {
|
||||
struct spi_device *spi;
|
||||
struct regmap *regmap;
|
||||
struct regulator *reg;
|
||||
/* Protect against concurrent accesses to the device and data content */
|
||||
struct mutex lock;
|
||||
int avdd_uv;
|
||||
int offset_uv;
|
||||
u8 bias;
|
||||
u8 gain;
|
||||
int offset_uv;
|
||||
bool refbuf_en;
|
||||
__le16 reg_val_16 __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
/* ADA4250 Current Bias Source Settings: Disabled, Bandgap Reference, AVDD */
|
||||
@@ -91,8 +92,7 @@ static int ada4250_set_offset_uv(struct iio_dev *indio_dev,
|
||||
if (st->bias == 0 || st->bias == 3)
|
||||
return -EINVAL;
|
||||
|
||||
voltage_v = regulator_get_voltage(st->reg);
|
||||
voltage_v = DIV_ROUND_CLOSEST(voltage_v, 1000000);
|
||||
voltage_v = DIV_ROUND_CLOSEST(st->avdd_uv, MICRO);
|
||||
|
||||
if (st->bias == ADA4250_BIAS_AVDD)
|
||||
x[0] = voltage_v;
|
||||
@@ -292,50 +292,33 @@ static const struct iio_chan_spec ada4250_channels[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static void ada4250_reg_disable(void *data)
|
||||
{
|
||||
regulator_disable(data);
|
||||
}
|
||||
|
||||
static int ada4250_init(struct ada4250_state *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
int ret;
|
||||
u16 chip_id;
|
||||
u8 data[2] __aligned(8) = {};
|
||||
struct spi_device *spi = st->spi;
|
||||
|
||||
st->refbuf_en = device_property_read_bool(&spi->dev, "adi,refbuf-enable");
|
||||
st->refbuf_en = device_property_read_bool(dev, "adi,refbuf-enable");
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "avdd");
|
||||
if (IS_ERR(st->reg))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(st->reg),
|
||||
st->avdd_uv = devm_regulator_get_enable_read_voltage(dev, "avdd");
|
||||
if (st->avdd_uv < 0)
|
||||
return dev_err_probe(dev, st->avdd_uv,
|
||||
"failed to get the AVDD voltage\n");
|
||||
|
||||
ret = regulator_enable(st->reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable specified AVDD supply\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ada4250_reg_disable, st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(st->regmap, ADA4250_REG_RESET,
|
||||
FIELD_PREP(ADA4250_RESET_MSK, 1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_read(st->regmap, ADA4250_REG_CHIP_ID, data, 2);
|
||||
ret = regmap_bulk_read(st->regmap, ADA4250_REG_CHIP_ID, &st->reg_val_16,
|
||||
sizeof(st->reg_val_16));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip_id = get_unaligned_le16(data);
|
||||
chip_id = le16_to_cpu(st->reg_val_16);
|
||||
|
||||
if (chip_id != ADA4250_CHIP_ID) {
|
||||
dev_err(&spi->dev, "Invalid chip ID.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (chip_id != ADA4250_CHIP_ID)
|
||||
dev_info(dev, "Invalid chip ID: 0x%02X.\n", chip_id);
|
||||
|
||||
return regmap_write(st->regmap, ADA4250_REG_REFBUF_EN,
|
||||
FIELD_PREP(ADA4250_REFBUF_MSK, st->refbuf_en));
|
||||
@@ -368,10 +351,8 @@ static int ada4250_probe(struct spi_device *spi)
|
||||
mutex_init(&st->lock);
|
||||
|
||||
ret = ada4250_init(st);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "ADA4250 init failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&spi->dev, ret, "ADA4250 init failed\n");
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) 2012 Analog Devices, Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*/
|
||||
|
||||
@@ -82,7 +82,7 @@ static const struct iio_chan_spec atlas_hum_ezo_channels[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct atlas_ezo_device atlas_ezo_devices[] = {
|
||||
static const struct atlas_ezo_device atlas_ezo_devices[] = {
|
||||
[ATLAS_CO2_EZO] = {
|
||||
.channels = atlas_co2_ezo_channels,
|
||||
.num_channels = 1,
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define ATLAS_REGMAP_NAME "atlas_regmap"
|
||||
#define ATLAS_DRV_NAME "atlas"
|
||||
|
||||
#define ATLAS_REG_DEV_TYPE 0x00
|
||||
@@ -96,7 +95,7 @@ struct atlas_data {
|
||||
};
|
||||
|
||||
static const struct regmap_config atlas_regmap_config = {
|
||||
.name = ATLAS_REGMAP_NAME,
|
||||
.name = "atlas_regmap",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
@@ -158,7 +158,7 @@ const struct regmap_config bme680_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.max_register = 0xef,
|
||||
.volatile_table = &bme680_volatile_table,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
};
|
||||
EXPORT_SYMBOL_NS(bme680_regmap_config, "IIO_BME680");
|
||||
|
||||
|
||||
@@ -587,7 +587,7 @@ static irqreturn_t scd30_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
int data[SCD30_MEAS_COUNT];
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
} scan = { };
|
||||
int ret;
|
||||
|
||||
mutex_lock(&state->lock);
|
||||
@@ -595,7 +595,6 @@ static irqreturn_t scd30_trigger_handler(int irq, void *p)
|
||||
ret = scd30_read_poll(state);
|
||||
else
|
||||
ret = scd30_read_meas(state);
|
||||
memset(&scan, 0, sizeof(scan));
|
||||
memcpy(scan.data, state->meas, sizeof(state->meas));
|
||||
mutex_unlock(&state->lock);
|
||||
if (ret)
|
||||
|
||||
@@ -665,10 +665,9 @@ static irqreturn_t scd4x_trigger_handler(int irq, void *p)
|
||||
struct {
|
||||
uint16_t data[3];
|
||||
aligned_s64 ts;
|
||||
} scan;
|
||||
} scan = { };
|
||||
int ret;
|
||||
|
||||
memset(&scan, 0, sizeof(scan));
|
||||
mutex_lock(&state->lock);
|
||||
ret = scd4x_read_poll(state, scan.data);
|
||||
mutex_unlock(&state->lock);
|
||||
|
||||
@@ -51,13 +51,12 @@ static int sunrise_regmap_read(void *context, const void *reg_buf,
|
||||
{
|
||||
struct i2c_client *client = context;
|
||||
struct sunrise_dev *sunrise = i2c_get_clientdata(client);
|
||||
union i2c_smbus_data data;
|
||||
union i2c_smbus_data data = { };
|
||||
int ret;
|
||||
|
||||
if (reg_size != 1 || !val_size)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.block[0] = val_size;
|
||||
|
||||
/*
|
||||
@@ -88,14 +87,13 @@ static int sunrise_regmap_write(void *context, const void *val_buf, size_t count
|
||||
{
|
||||
struct i2c_client *client = context;
|
||||
struct sunrise_dev *sunrise = i2c_get_clientdata(client);
|
||||
union i2c_smbus_data data;
|
||||
union i2c_smbus_data data = { };
|
||||
|
||||
/* Discard reg address from values count. */
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
count--;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.block[0] = count;
|
||||
memcpy(&data.block[1], (u8 *)val_buf + 1, count);
|
||||
|
||||
|
||||
@@ -30,3 +30,12 @@ config IIO_CROS_EC_SENSORS_LID_ANGLE
|
||||
convertible devices.
|
||||
This module is loaded when the EC can calculate the angle between the base
|
||||
and the lid.
|
||||
|
||||
config IIO_CROS_EC_ACTIVITY
|
||||
tristate "ChromeOS EC Activity Sensors"
|
||||
depends on IIO_CROS_EC_SENSORS_CORE
|
||||
help
|
||||
Module to handle activity events presented by the ChromeOS EC sensor hub.
|
||||
Activities can be a proximity detector (on body/off body detection)
|
||||
or a significant motion detector.
|
||||
Creates an IIO device to manage all activities.
|
||||
|
||||
@@ -7,3 +7,4 @@ cros-ec-sensors-core-objs += cros_ec_sensors_core.o cros_ec_sensors_trace.o
|
||||
obj-$(CONFIG_IIO_CROS_EC_SENSORS_CORE) += cros-ec-sensors-core.o
|
||||
obj-$(CONFIG_IIO_CROS_EC_SENSORS) += cros_ec_sensors.o
|
||||
obj-$(CONFIG_IIO_CROS_EC_SENSORS_LID_ANGLE) += cros_ec_lid_angle.o
|
||||
obj-$(CONFIG_IIO_CROS_EC_ACTIVITY) += cros_ec_activity.o
|
||||
|
||||
307
drivers/iio/common/cros_ec_sensors/cros_ec_activity.c
Normal file
307
drivers/iio/common/cros_ec_sensors/cros_ec_activity.c
Normal file
@@ -0,0 +1,307 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* cros_ec_activity - Driver for activities/gesture recognition.
|
||||
*
|
||||
* Copyright 2025 Google, Inc
|
||||
*
|
||||
* This driver uses the cros-ec interface to communicate with the ChromeOS
|
||||
* EC about activity data.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/platform_data/cros_ec_commands.h>
|
||||
#include <linux/platform_data/cros_ec_proto.h>
|
||||
|
||||
#include <linux/iio/common/cros_ec_sensors_core.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
#define DRV_NAME "cros-ec-activity"
|
||||
|
||||
/* state data for ec_sensors iio driver. */
|
||||
struct cros_ec_sensors_state {
|
||||
/* Shared by all sensors */
|
||||
struct cros_ec_sensors_core_state core;
|
||||
|
||||
struct iio_chan_spec *channels;
|
||||
|
||||
int body_detection_channel_index;
|
||||
int sig_motion_channel_index;
|
||||
};
|
||||
|
||||
static const struct iio_event_spec cros_ec_activity_single_shot[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_CHANGE,
|
||||
/* significant motion trigger when we get out of still. */
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec cros_ec_body_detect_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_CHANGE,
|
||||
.dir = IIO_EV_DIR_EITHER,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static int cros_ec_activity_sensors_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct cros_ec_sensors_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (chan->type != IIO_PROXIMITY || mask != IIO_CHAN_INFO_RAW)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&st->core.cmd_lock);
|
||||
st->core.param.cmd = MOTIONSENSE_CMD_GET_ACTIVITY;
|
||||
st->core.param.get_activity.activity =
|
||||
MOTIONSENSE_ACTIVITY_BODY_DETECTION;
|
||||
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* EC actually report if a body is near (1) or far (0).
|
||||
* Units for proximity sensor after scale is in meter,
|
||||
* so invert the result to return 0m when near and 1m when far.
|
||||
*/
|
||||
*val = !st->core.resp->get_activity.state;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int cros_ec_activity_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 cros_ec_sensors_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (chan->type != IIO_ACTIVITY && chan->type != IIO_PROXIMITY)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&st->core.cmd_lock);
|
||||
st->core.param.cmd = MOTIONSENSE_CMD_LIST_ACTIVITIES;
|
||||
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
return !!(st->core.resp->list_activities.enabled &
|
||||
(1 << MOTIONSENSE_ACTIVITY_BODY_DETECTION));
|
||||
case IIO_ACTIVITY:
|
||||
if (chan->channel2 == IIO_MOD_STILL) {
|
||||
return !!(st->core.resp->list_activities.enabled &
|
||||
(1 << MOTIONSENSE_ACTIVITY_SIG_MOTION));
|
||||
}
|
||||
|
||||
dev_warn(&indio_dev->dev, "Unknown activity: %d\n",
|
||||
chan->channel2);
|
||||
return -EINVAL;
|
||||
default:
|
||||
dev_warn(&indio_dev->dev, "Unknown channel type: %d\n",
|
||||
chan->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int cros_ec_activity_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 cros_ec_sensors_state *st = iio_priv(indio_dev);
|
||||
|
||||
guard(mutex)(&st->core.cmd_lock);
|
||||
st->core.param.cmd = MOTIONSENSE_CMD_SET_ACTIVITY;
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
st->core.param.set_activity.activity =
|
||||
MOTIONSENSE_ACTIVITY_BODY_DETECTION;
|
||||
break;
|
||||
case IIO_ACTIVITY:
|
||||
if (chan->channel2 == IIO_MOD_STILL) {
|
||||
st->core.param.set_activity.activity =
|
||||
MOTIONSENSE_ACTIVITY_SIG_MOTION;
|
||||
break;
|
||||
}
|
||||
dev_warn(&indio_dev->dev, "Unknown activity: %d\n",
|
||||
chan->channel2);
|
||||
return -EINVAL;
|
||||
default:
|
||||
dev_warn(&indio_dev->dev, "Unknown channel type: %d\n",
|
||||
chan->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
st->core.param.set_activity.enable = state;
|
||||
return cros_ec_motion_send_host_cmd(&st->core, 0);
|
||||
}
|
||||
|
||||
static int cros_ec_activity_push_data(struct iio_dev *indio_dev,
|
||||
s16 *data, s64 timestamp)
|
||||
{
|
||||
struct ec_response_activity_data *activity_data =
|
||||
(struct ec_response_activity_data *)data;
|
||||
enum motionsensor_activity activity = activity_data->activity;
|
||||
u8 state = activity_data->state;
|
||||
const struct cros_ec_sensors_state *st = iio_priv(indio_dev);
|
||||
const struct iio_chan_spec *chan;
|
||||
enum iio_event_direction dir;
|
||||
int index;
|
||||
|
||||
switch (activity) {
|
||||
case MOTIONSENSE_ACTIVITY_BODY_DETECTION:
|
||||
index = st->body_detection_channel_index;
|
||||
dir = state ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
|
||||
break;
|
||||
case MOTIONSENSE_ACTIVITY_SIG_MOTION:
|
||||
index = st->sig_motion_channel_index;
|
||||
dir = IIO_EV_DIR_FALLING;
|
||||
break;
|
||||
default:
|
||||
dev_warn(&indio_dev->dev, "Unknown activity: %d\n", activity);
|
||||
return 0;
|
||||
}
|
||||
chan = &st->channels[index];
|
||||
iio_push_event(indio_dev,
|
||||
IIO_UNMOD_EVENT_CODE(chan->type, index, chan->event_spec[0].type, dir),
|
||||
timestamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t cros_ec_activity_capture(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
|
||||
/*
|
||||
* This callback would be called when a software trigger is
|
||||
* used. But when this virtual sensor is present, it is guaranteed
|
||||
* the sensor hub is advanced enough to not need a software trigger.
|
||||
*/
|
||||
dev_warn(&indio_dev->dev, "%s: Not Expected\n", __func__);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static const struct iio_info ec_sensors_info = {
|
||||
.read_raw = &cros_ec_activity_sensors_read_raw,
|
||||
.read_event_config = cros_ec_activity_read_event_config,
|
||||
.write_event_config = cros_ec_activity_write_event_config,
|
||||
};
|
||||
|
||||
static int cros_ec_sensors_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_device *ec_device = dev_get_drvdata(dev->parent);
|
||||
struct iio_dev *indio_dev;
|
||||
struct cros_ec_sensors_state *st;
|
||||
struct iio_chan_spec *channel;
|
||||
unsigned long activities;
|
||||
int i, index, ret, nb_activities;
|
||||
|
||||
if (!ec_device) {
|
||||
dev_warn(dev, "No CROS EC device found.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
|
||||
cros_ec_activity_capture);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->info = &ec_sensors_info;
|
||||
st = iio_priv(indio_dev);
|
||||
st->core.type = st->core.resp->info.type;
|
||||
st->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
|
||||
|
||||
st->core.param.cmd = MOTIONSENSE_CMD_LIST_ACTIVITIES;
|
||||
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
activities = st->core.resp->list_activities.enabled |
|
||||
st->core.resp->list_activities.disabled;
|
||||
if (!activities)
|
||||
return -ENODEV;
|
||||
|
||||
/* Allocate a channel per activity and one for timestamp */
|
||||
nb_activities = hweight_long(activities) + 1;
|
||||
st->channels = devm_kcalloc(dev, nb_activities,
|
||||
sizeof(*st->channels), GFP_KERNEL);
|
||||
if (!st->channels)
|
||||
return -ENOMEM;
|
||||
|
||||
channel = &st->channels[0];
|
||||
index = 0;
|
||||
for_each_set_bit(i, &activities, BITS_PER_LONG) {
|
||||
/* List all available triggers */
|
||||
if (i == MOTIONSENSE_ACTIVITY_BODY_DETECTION) {
|
||||
channel->type = IIO_PROXIMITY;
|
||||
channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
|
||||
channel->event_spec = cros_ec_body_detect_events;
|
||||
channel->num_event_specs =
|
||||
ARRAY_SIZE(cros_ec_body_detect_events);
|
||||
st->body_detection_channel_index = index;
|
||||
} else {
|
||||
channel->type = IIO_ACTIVITY;
|
||||
channel->modified = 1;
|
||||
channel->event_spec = cros_ec_activity_single_shot;
|
||||
channel->num_event_specs =
|
||||
ARRAY_SIZE(cros_ec_activity_single_shot);
|
||||
if (i == MOTIONSENSE_ACTIVITY_SIG_MOTION) {
|
||||
channel->channel2 = IIO_MOD_STILL;
|
||||
st->sig_motion_channel_index = index;
|
||||
} else {
|
||||
dev_warn(dev, "Unknown activity: %d\n", i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
channel->ext_info = cros_ec_sensors_limited_info;
|
||||
channel->scan_index = index++;
|
||||
channel++;
|
||||
}
|
||||
|
||||
/* Timestamp */
|
||||
channel->scan_index = index;
|
||||
channel->type = IIO_TIMESTAMP;
|
||||
channel->channel = -1;
|
||||
channel->scan_type.sign = 's';
|
||||
channel->scan_type.realbits = 64;
|
||||
channel->scan_type.storagebits = 64;
|
||||
|
||||
indio_dev->channels = st->channels;
|
||||
indio_dev->num_channels = index + 1;
|
||||
|
||||
return cros_ec_sensors_core_register(dev, indio_dev,
|
||||
cros_ec_activity_push_data);
|
||||
}
|
||||
|
||||
static struct platform_driver cros_ec_sensors_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
.probe = cros_ec_sensors_probe,
|
||||
};
|
||||
module_platform_driver(cros_ec_sensors_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ChromeOS EC activity sensors driver");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -486,6 +486,16 @@ const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[] = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_ext_info);
|
||||
|
||||
const struct iio_chan_spec_ext_info cros_ec_sensors_limited_info[] = {
|
||||
{
|
||||
.name = "id",
|
||||
.shared = IIO_SHARED_BY_ALL,
|
||||
.read = cros_ec_sensors_id
|
||||
},
|
||||
{ }
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(cros_ec_sensors_limited_info);
|
||||
|
||||
/**
|
||||
* cros_ec_sensors_idx_to_reg - convert index into offset in shared memory
|
||||
* @st: pointer to state information for device
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
static struct {
|
||||
static const struct {
|
||||
u32 usage_id;
|
||||
int unit; /* 0 for default others from HID sensor spec */
|
||||
int scale_val0; /* scale, whole number */
|
||||
|
||||
@@ -293,10 +293,9 @@ static irqreturn_t ad3552r_trigger_handler(int irq, void *p)
|
||||
struct iio_buffer *buf = indio_dev->buffer;
|
||||
struct ad3552r_desc *dac = iio_priv(indio_dev);
|
||||
/* Maximum size of a scan */
|
||||
u8 buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE];
|
||||
u8 buff[AD3552R_MAX_CH * AD3552R_MAX_REG_SIZE] = { };
|
||||
int err;
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
err = iio_pop_from_buffer(buf, buff);
|
||||
if (err)
|
||||
goto end;
|
||||
|
||||
@@ -426,7 +426,7 @@ static const struct regmap_config ad5380_regmap_config = {
|
||||
.val_bits = 14,
|
||||
|
||||
.max_register = AD5380_REG_DATA(40),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
|
||||
.volatile_reg = ad5380_reg_false,
|
||||
.readable_reg = ad5380_reg_false,
|
||||
|
||||
@@ -155,7 +155,7 @@ struct ad5770r_output_modes {
|
||||
int max;
|
||||
};
|
||||
|
||||
static struct ad5770r_output_modes ad5770r_rng_tbl[] = {
|
||||
static const struct ad5770r_output_modes ad5770r_rng_tbl[] = {
|
||||
{ 0, AD5770R_CH0_0_300, 0, 300 },
|
||||
{ 0, AD5770R_CH0_NEG_60_0, -60, 0 },
|
||||
{ 0, AD5770R_CH0_NEG_60_300, -60, 300 },
|
||||
|
||||
@@ -635,15 +635,26 @@ static int axi_dac_ddr_disable(struct iio_backend *back)
|
||||
AXI_DAC_CNTRL_2_SDR_DDR_N);
|
||||
}
|
||||
|
||||
static int axi_dac_wait_bus_free(struct axi_dac_state *st)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(st->regmap, AXI_DAC_UI_STATUS_REG, val,
|
||||
FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, val) == 0, 10,
|
||||
100 * KILO);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_err(st->dev, "AXI bus timeout\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int axi_dac_data_stream_enable(struct iio_backend *back)
|
||||
{
|
||||
struct axi_dac_state *st = iio_backend_get_priv(back);
|
||||
int ret, val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(st->regmap,
|
||||
AXI_DAC_UI_STATUS_REG, val,
|
||||
FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, val) == 0,
|
||||
10, 100 * KILO);
|
||||
ret = axi_dac_wait_bus_free(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -734,12 +745,9 @@ static int __axi_dac_bus_reg_write(struct iio_backend *back, u32 reg,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(st->regmap,
|
||||
AXI_DAC_UI_STATUS_REG, ival,
|
||||
FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0,
|
||||
10, 100 * KILO);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_err(st->dev, "AXI read timeout\n");
|
||||
ret = axi_dac_wait_bus_free(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Cleaning always AXI_DAC_CUSTOM_CTRL_TRANSFER_DATA */
|
||||
return regmap_clear_bits(st->regmap, AXI_DAC_CUSTOM_CTRL_REG,
|
||||
@@ -760,7 +768,6 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
|
||||
{
|
||||
struct axi_dac_state *st = iio_backend_get_priv(back);
|
||||
int ret;
|
||||
u32 ival;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
@@ -773,10 +780,7 @@ static int axi_dac_bus_reg_read(struct iio_backend *back, u32 reg, u32 *val,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(st->regmap,
|
||||
AXI_DAC_UI_STATUS_REG, ival,
|
||||
FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0,
|
||||
10, 100 * KILO);
|
||||
ret = axi_dac_wait_bus_free(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -787,7 +791,7 @@ static int axi_dac_bus_set_io_mode(struct iio_backend *back,
|
||||
enum ad3552r_io_mode mode)
|
||||
{
|
||||
struct axi_dac_state *st = iio_backend_get_priv(back);
|
||||
int ival, ret;
|
||||
int ret;
|
||||
|
||||
if (mode > AD3552R_IO_MODE_QSPI)
|
||||
return -EINVAL;
|
||||
@@ -800,9 +804,7 @@ static int axi_dac_bus_set_io_mode(struct iio_backend *back,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_read_poll_timeout(st->regmap, AXI_DAC_UI_STATUS_REG, ival,
|
||||
FIELD_GET(AXI_DAC_UI_STATUS_IF_BUSY, ival) == 0, 10,
|
||||
100 * KILO);
|
||||
return axi_dac_wait_bus_free(st);
|
||||
}
|
||||
|
||||
static void axi_dac_child_remove(void *data)
|
||||
|
||||
@@ -622,7 +622,7 @@ static const struct iio_chan_spec_ext_info ltc2688_toggle_ext_info[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = {
|
||||
static const struct iio_chan_spec_ext_info ltc2688_dither_ext_info[] = {
|
||||
LTC2688_CHAN_EXT_INFO("dither_raw", LTC2688_INPUT_B, IIO_SEPARATE,
|
||||
ltc2688_dac_input_read, ltc2688_dac_input_write),
|
||||
LTC2688_CHAN_EXT_INFO("dither_raw_available", LTC2688_INPUT_B_AVAIL,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user