mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 20:24:12 +08:00
Staging / IIO driver patches for 5.14-rc1
Here is the big set of IIO and staging driver patches for 5.14-rc1. Loads of IIO driver updates and additions in here, the shortlog has the full details. For the staging side, we moved a few drivers out of staging, and deleted the kpc2000 drivers as the original developer asked us to because no one was working on them anymore. Also in here are loads of coding style cleanups due to different intern projects focusing on the staging tree to try to get experience doing kernel development. All of these have been in the linux-next tree for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYOM50w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykZ4wCeK/JreZijlAy0O5Gq1equvRx1jJoAoJmmt7UY bx6qpcmUM7c53cMXr/kh =6suo -----END PGP SIGNATURE----- Merge tag 'staging-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging Pull staging / IIO driver updates from Greg KH: "Here is the big set of IIO and staging driver patches for 5.14-rc1. Loads of IIO driver updates and additions in here, the shortlog has the full details. For the staging side, we moved a few drivers out of staging, and deleted the kpc2000 drivers as the original developer asked us to because no one was working on them anymore. Also in here are loads of coding style cleanups due to different intern projects focusing on the staging tree to try to get experience doing kernel development. All of these have been in the linux-next tree for a while with no reported problems" * tag 'staging-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (744 commits) staging: hi6421-spmi-pmic: cleanup some macros staging: hi6421-spmi-pmic: change identation of a table staging: hi6421-spmi-pmic: change a return code staging: hi6421-spmi-pmic: better name IRQs staging: hi6421-spmi-pmic: use devm_request_threaded_irq() staging: hisilicon,hi6421-spmi-pmic.yaml: cleanup descriptions spmi: hisi-spmi-controller: move driver from staging phy: phy-hi3670-usb3: move driver from staging into phy staging: rtl8188eu: remove include/rtw_debug.h header staging: rtl8188eu: remove GlobalDebugLevel variable staging: rtl8188eu: remove DRIVER_PREFIX preprocessor definition staging: rtl8188eu: remove RT_TRACE macro staging: rtl8188eu: remove all RT_TRACE calls from hal/rtl8188eu_recv.c staging: rtl8188eu: remove all RT_TRACE calls from hal/hal_intf.c staging: rtl8188eu: remove all RT_TRACE calls from hal/rtl8188eu_xmit.c staging: rtl8188eu: remove all RT_TRACE calls from core/rtw_xmit.c staging: rtl8188eu: remove all RT_TRACE calls from core/rtw_pwrctrl.c staging: rtl8188eu: remove all RT_TRACE calls from core/rtw_recv.c staging: rtl8188eu: remove all RT_TRACE calls from core/rtw_ioctl_set.c staging: rtl8188eu: remove all RT_TRACE calls from core/rtw_ieee80211.c ...
This commit is contained in:
commit
a16d8644ba
182
Documentation/ABI/obsolete/sysfs-bus-iio
Normal file
182
Documentation/ABI/obsolete/sysfs-bus-iio
Normal file
@ -0,0 +1,182 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/length
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Number of scans contained by the buffer.
|
||||
|
||||
Since Kernel 5.11, multiple buffers are supported.
|
||||
so, it is better to use, instead:
|
||||
/sys/bus/iio/devices/iio:deviceX/bufferY/length
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/enable
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Actually start the buffer capture up. Will start trigger
|
||||
if first device and appropriate.
|
||||
|
||||
Since Kernel 5.11, multiple buffers are supported.
|
||||
so, it is better to use, instead:
|
||||
/sys/bus/iio/devices/iio:deviceX/bufferY/enable
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/scan_elements
|
||||
KernelVersion: 2.6.37
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Directory containing interfaces for elements that will be
|
||||
captured for a single triggered sample set in the buffer.
|
||||
|
||||
Since kernel 5.11 the scan_elements attributes are merged into
|
||||
the bufferY directory, to be configurable per buffer.
|
||||
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_en
|
||||
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
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_proximity_en
|
||||
KernelVersion: 2.6.37
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Scan element control for triggered data capture.
|
||||
|
||||
Since kernel 5.11 the scan_elements attributes are merged into
|
||||
the bufferY directory, to be configurable per buffer.
|
||||
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_type
|
||||
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
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_proximity_type
|
||||
KernelVersion: 2.6.37
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Description of the scan element data storage within the buffer
|
||||
and hence the form in which it is read from user-space.
|
||||
Form is [be|le]:[s|u]bits/storagebits[>>shift].
|
||||
be or le specifies big or little endian. s or u specifies if
|
||||
signed (2's complement) or unsigned. bits is the number of bits
|
||||
of data and storagebits is the space (after padding) that it
|
||||
occupies in the buffer. shift if specified, is the shift that
|
||||
needs to be applied prior to masking out unused bits. Some
|
||||
devices put their data in the middle of the transferred elements
|
||||
with additional information on both sides. Note that some
|
||||
devices will have additional information in the unused bits
|
||||
so to get a clean value, the bits value must be used to mask
|
||||
the buffer output value appropriately. The storagebits value
|
||||
also specifies the data alignment. So s48/64>>2 will be a
|
||||
signed 48 bit integer stored in a 64 bit location aligned to
|
||||
a 64 bit boundary. To obtain the clean value, shift right 2
|
||||
and apply a mask to zero the top 16 bits of the result.
|
||||
For other storage combinations this attribute will be extended
|
||||
appropriately.
|
||||
|
||||
Since kernel 5.11 the scan_elements attributes are merged into
|
||||
the bufferY directory, to be configurable per buffer.
|
||||
|
||||
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
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_proximity_index
|
||||
KernelVersion: 2.6.37
|
||||
Description:
|
||||
A single positive integer specifying the position of this
|
||||
scan element in the buffer. Note these are not dependent on
|
||||
what is enabled and may not be contiguous. Thus for user-space
|
||||
to establish the full layout these must be used in conjunction
|
||||
with all _en attributes to establish which channels are present,
|
||||
and the relevant _type attributes to establish the data storage
|
||||
format.
|
||||
|
||||
Since kernel 5.11 the scan_elements attributes are merged into
|
||||
the bufferY directory, to be configurable per buffer.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/watermark
|
||||
KernelVersion: 4.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A single positive integer specifying the maximum number of scan
|
||||
elements to wait for.
|
||||
|
||||
Poll will block until the watermark is reached.
|
||||
|
||||
Blocking read will wait until the minimum between the requested
|
||||
read amount or the low water mark is available.
|
||||
|
||||
Non-blocking read will retrieve the available samples from the
|
||||
buffer even if there are less samples then watermark level. This
|
||||
allows the application to block on poll with a timeout and read
|
||||
the available samples after the timeout expires and thus have a
|
||||
maximum delay guarantee.
|
||||
|
||||
Since Kernel 5.11, multiple buffers are supported.
|
||||
so, it is better to use, instead:
|
||||
/sys/bus/iio/devices/iio:deviceX/bufferY/watermark
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/data_available
|
||||
KernelVersion: 4.16
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
A read-only value indicating the bytes of data available in the
|
||||
buffer. In the case of an output buffer, this indicates the
|
||||
amount of empty space available to write data to. In the case of
|
||||
an input buffer, this indicates the amount of data available for
|
||||
reading.
|
||||
|
||||
Since Kernel 5.11, multiple buffers are supported.
|
||||
so, it is better to use, instead:
|
||||
/sys/bus/iio/devices/iio:deviceX/bufferY/data_available
|
@ -57,6 +57,7 @@ Description:
|
||||
What: /sys/bus/counter/devices/counterX/countY/count_mode_available
|
||||
What: /sys/bus/counter/devices/counterX/countY/error_noise_available
|
||||
What: /sys/bus/counter/devices/counterX/countY/function_available
|
||||
What: /sys/bus/counter/devices/counterX/countY/prescaler_available
|
||||
What: /sys/bus/counter/devices/counterX/countY/signalZ_action_available
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -154,6 +155,15 @@ Description:
|
||||
Count Y. If possible, this should match the name of the
|
||||
respective channel as it appears in the device datasheet.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/countY/prescaler
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Configure the prescaler value associated with Count Y.
|
||||
On the FlexTimer, the counter clock source passes through a
|
||||
prescaler (i.e. a counter). This acts like a clock
|
||||
divider.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/countY/preset
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -193,6 +203,15 @@ Description:
|
||||
both edges:
|
||||
Any state transition.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/countY/spike_filter_ns
|
||||
KernelVersion: 5.14
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
If the counter device supports programmable spike filter this
|
||||
attribute indicates the value in nanoseconds where noise pulses
|
||||
shorter or equal to configured value are ignored. Value 0 means
|
||||
filter is disabled.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/name
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -215,11 +234,45 @@ Description:
|
||||
Read-only attribute that indicates the total number of Signals
|
||||
belonging to the Counter.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/signal
|
||||
What: /sys/bus/counter/devices/counterX/signalY/cable_fault
|
||||
KernelVersion: 5.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Read-only attribute that indicates whether a differential
|
||||
encoder cable fault (not connected or loose wires) is detected
|
||||
for the respective channel of Signal Y. Valid attribute values
|
||||
are boolean. Detection must first be enabled via the
|
||||
corresponding cable_fault_enable attribute.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable
|
||||
KernelVersion: 5.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Whether detection of differential encoder cable faults for the
|
||||
respective channel of Signal Y is enabled. Valid attribute
|
||||
values are boolean.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler
|
||||
KernelVersion: 5.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Filter clock factor for input Signal Y. This prescaler value
|
||||
affects the inputs of both quadrature pair signals.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/index_polarity
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Signal data of Signal Y represented as a string.
|
||||
Active level of index input Signal Y; irrelevant in
|
||||
non-synchronous load mode.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/index_polarity_available
|
||||
What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_available
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Discrete set of available values for the respective Signal Y
|
||||
configuration are listed in this file.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/name
|
||||
KernelVersion: 5.2
|
||||
@ -228,3 +281,31 @@ Description:
|
||||
Read-only attribute that indicates the device-specific name of
|
||||
Signal Y. If possible, this should match the name of the
|
||||
respective signal as it appears in the device datasheet.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/signal
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Signal data of Signal Y represented as a string.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Configure the counter associated with Signal Y for
|
||||
non-synchronous or synchronous load mode. Synchronous load mode
|
||||
cannot be selected in non-quadrature (Pulse-Direction) clock
|
||||
mode.
|
||||
|
||||
non-synchronous:
|
||||
A logic low level is the active level at this index
|
||||
input. The index function (as enabled via preset_enable)
|
||||
is performed directly on the active level of the index
|
||||
input.
|
||||
|
||||
synchronous:
|
||||
Intended for interfacing with encoder Index output in
|
||||
quadrature clock mode. The active level is configured
|
||||
via index_polarity. The index function (as enabled via
|
||||
preset_enable) is performed synchronously with the
|
||||
quadrature clock on the active level of the index input.
|
||||
|
@ -1,61 +0,0 @@
|
||||
What: /sys/bus/counter/devices/counterX/signalY/cable_fault
|
||||
KernelVersion: 5.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Read-only attribute that indicates whether a differential
|
||||
encoder cable fault (not connected or loose wires) is detected
|
||||
for the respective channel of Signal Y. Valid attribute values
|
||||
are boolean. Detection must first be enabled via the
|
||||
corresponding cable_fault_enable attribute.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable
|
||||
KernelVersion: 5.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Whether detection of differential encoder cable faults for the
|
||||
respective channel of Signal Y is enabled. Valid attribute
|
||||
values are boolean.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler
|
||||
KernelVersion: 5.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Filter clock factor for input Signal Y. This prescaler value
|
||||
affects the inputs of both quadrature pair signals.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/index_polarity
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Active level of index input Signal Y; irrelevant in
|
||||
non-synchronous load mode.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/index_polarity_available
|
||||
What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_available
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Discrete set of available values for the respective Signal Y
|
||||
configuration are listed in this file.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Configure the counter associated with Signal Y for
|
||||
non-synchronous or synchronous load mode. Synchronous load mode
|
||||
cannot be selected in non-quadrature (Pulse-Direction) clock
|
||||
mode.
|
||||
|
||||
non-synchronous:
|
||||
A logic low level is the active level at this index
|
||||
input. The index function (as enabled via preset_enable)
|
||||
is performed directly on the active level of the index
|
||||
input.
|
||||
|
||||
synchronous:
|
||||
Intended for interfacing with encoder Index output in
|
||||
quadrature clock mode. The active level is configured
|
||||
via index_polarity. The index function (as enabled via
|
||||
preset_enable) is performed synchronously with the
|
||||
quadrature clock on the active level of the index input.
|
@ -1,16 +0,0 @@
|
||||
What: /sys/bus/counter/devices/counterX/countY/prescaler_available
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Discrete set of available values for the respective Count Y
|
||||
configuration are listed in this file. Values are delimited by
|
||||
newline characters.
|
||||
|
||||
What: /sys/bus/counter/devices/counterX/countY/prescaler
|
||||
KernelVersion: 5.2
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Configure the prescaler value associated with Count Y.
|
||||
On the FlexTimer, the counter clock source passes through a
|
||||
prescaler (i.e. a counter). This acts like a clock
|
||||
divider.
|
@ -455,6 +455,19 @@ Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Hardware applied calibration offset (assumed to fix production
|
||||
inaccuracies).
|
||||
icm42600: For this device values are real physical offsets
|
||||
expressed in SI units (m/s^2 for accelerometers and rad/s
|
||||
for gyroscope)/
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available
|
||||
KernelVersion: 5.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Available values of calibbias. Maybe expressed as either of:
|
||||
|
||||
- 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_calibscale
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
|
||||
@ -652,6 +665,25 @@ Description:
|
||||
Output frequency for channel Y in Hz. The number must always be
|
||||
specified and unique if the output corresponds to a single
|
||||
channel.
|
||||
Some drivers have additional constraints:
|
||||
ADF4371 has an integrated VCO with fundamendal output
|
||||
frequency ranging from 4000000000 Hz 8000000000 Hz.
|
||||
|
||||
out_altvoltage0_frequency:
|
||||
A divide by 1, 2, 4, 8, 16, 32 or circuit generates
|
||||
frequencies from 62500000 Hz to 8000000000 Hz.
|
||||
out_altvoltage1_frequency:
|
||||
This channel duplicates the channel 0 frequency
|
||||
out_altvoltage2_frequency:
|
||||
A frequency doubler generates frequencies from
|
||||
8000000000 Hz to 16000000000 Hz.
|
||||
out_altvoltage3_frequency:
|
||||
A frequency quadrupler generates frequencies from
|
||||
16000000000 Hz to 32000000000 Hz.
|
||||
|
||||
Note: writes to one of the channels will affect the frequency of
|
||||
all the other channels, since it involves changing the VCO
|
||||
fundamental output frequency.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_phase
|
||||
KernelVersion: 3.4.0
|
||||
@ -663,6 +695,17 @@ Description:
|
||||
specified and unique if the output corresponds to a single
|
||||
channel.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw
|
||||
Date: May 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set/get output current for channel Y. Units after application
|
||||
of scale and offset are milliamps.
|
||||
For some devices current channels are used to specify
|
||||
current supplied to elements used in taking a measurement
|
||||
of a different type. E.g. LED currents.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/events
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -1195,16 +1238,12 @@ Description:
|
||||
The name of the trigger source being used, as per string given
|
||||
in /sys/class/iio/triggerY/name.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/length
|
||||
KernelVersion: 2.6.35
|
||||
What: /sys/bus/iio/devices/iio:deviceX/bufferY/length
|
||||
KernelVersion: 5.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Number of scans contained by the buffer.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/enable
|
||||
KernelVersion: 2.6.35
|
||||
What: /sys/bus/iio/devices/iio:deviceX/bufferY/enable
|
||||
KernelVersion: 5.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -1212,8 +1251,6 @@ Description:
|
||||
Actually start the buffer capture up. Will start trigger
|
||||
if first device and appropriate.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/scan_elements
|
||||
KernelVersion: 2.6.37
|
||||
What: /sys/bus/iio/devices/iio:deviceX/bufferY
|
||||
KernelVersion: 5.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -1224,34 +1261,6 @@ Description:
|
||||
Since kernel 5.11 the scan_elements attributes are merged into
|
||||
the bufferY directory, to be configurable per buffer.
|
||||
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_en
|
||||
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
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_en
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_proximity_en
|
||||
KernelVersion: 2.6.37
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_x_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_y_en
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_z_en
|
||||
@ -1284,23 +1293,6 @@ Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Scan element control for triggered data capture.
|
||||
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_accel_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_type
|
||||
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
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_type
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_proximity_type
|
||||
KernelVersion: 2.6.37
|
||||
What: /sys/.../iio:deviceX/bufferY/in_accel_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_anglvel_type
|
||||
What: /sys/.../iio:deviceX/bufferY/in_magn_type
|
||||
@ -1347,33 +1339,6 @@ Description:
|
||||
If the type parameter can take one of a small set of values,
|
||||
this attribute lists them.
|
||||
|
||||
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
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_pressure_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_rot_quaternion_index
|
||||
What: /sys/.../iio:deviceX/scan_elements/in_proximity_index
|
||||
KernelVersion: 2.6.37
|
||||
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
|
||||
@ -1613,8 +1578,6 @@ Description:
|
||||
Specifies number of seconds in which we compute the steps
|
||||
that occur in order to decide if the consumer is making steps.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/watermark
|
||||
KernelVersion: 4.2
|
||||
What: /sys/bus/iio/devices/iio:deviceX/bufferY/watermark
|
||||
KernelVersion: 5.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -1633,8 +1596,6 @@ Description:
|
||||
the available samples after the timeout expires and thus have a
|
||||
maximum delay guarantee.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/buffer/data_available
|
||||
KernelVersion: 4.16
|
||||
What: /sys/bus/iio/devices/iio:deviceX/bufferY/data_available
|
||||
KernelVersion: 5.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
|
@ -1,28 +1,3 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_frequency
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Stores the PLL frequency in Hz for channel Y.
|
||||
Reading returns the actual frequency in Hz.
|
||||
The ADF4371 has an integrated VCO with fundamendal output
|
||||
frequency ranging from 4000000000 Hz 8000000000 Hz.
|
||||
|
||||
out_altvoltage0_frequency:
|
||||
A divide by 1, 2, 4, 8, 16, 32 or circuit generates
|
||||
frequencies from 62500000 Hz to 8000000000 Hz.
|
||||
out_altvoltage1_frequency:
|
||||
This channel duplicates the channel 0 frequency
|
||||
out_altvoltage2_frequency:
|
||||
A frequency doubler generates frequencies from
|
||||
8000000000 Hz to 16000000000 Hz.
|
||||
out_altvoltage3_frequency:
|
||||
A frequency quadrupler generates frequencies from
|
||||
16000000000 Hz to 32000000000 Hz.
|
||||
|
||||
Note: writes to one of the channels will affect the frequency of
|
||||
all the other channels, since it involves changing the VCO
|
||||
fundamental output frequency.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_name
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@ -34,11 +9,3 @@ Description:
|
||||
out_altvoltage2_name: RF16x
|
||||
out_altvoltage3_name: RF32x
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_powerdown
|
||||
KernelVersion:
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This attribute allows the user to power down the PLL and it's
|
||||
RFOut buffers.
|
||||
Writing 1 causes the specified channel to power down.
|
||||
Clearing returns to normal operation.
|
||||
|
@ -18,6 +18,8 @@ Description:
|
||||
respectively which simply helper channels containing the
|
||||
calculated difference in the value of stage 1 - 2 and 3 - 4.
|
||||
The values are expressed in 24-bit twos complement.
|
||||
The LED current for the stage is controlled via
|
||||
out_currentY_raw.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_intensityY_offset
|
||||
Date: May 2016
|
||||
@ -35,11 +37,3 @@ Contact: Andrew F. Davis <afd@ti.com>
|
||||
Description:
|
||||
Get and set the resistance and the capacitance settings for the
|
||||
Transimpedance Amplifier during the associated stage.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw
|
||||
Date: May 2016
|
||||
KernelVersion:
|
||||
Contact: Andrew F. Davis <afd@ti.com>
|
||||
Description:
|
||||
Get and set the LED current for the specified LED active during
|
||||
this stage. Y is the specific stage number.
|
||||
|
@ -1,20 +0,0 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
|
||||
KernelVersion: 5.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Hardware applied calibration offset (assumed to fix production
|
||||
inaccuracies). Values represent a real physical offset expressed
|
||||
in SI units (m/s^2 for accelerometer and rad/s for gyroscope).
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available
|
||||
KernelVersion: 5.8
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Range of available values for hardware offset. Values in SI
|
||||
units (m/s^2 for accelerometer and rad/s for gyroscope).
|
@ -41,14 +41,6 @@ Description:
|
||||
Get the current light zone (0..4) as defined by the
|
||||
in_illuminance0_threshY_{falling,rising} thresholds.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_raw
|
||||
Date: May 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Get output current for channel Y (0..255), that is,
|
||||
out_currentY_currentZ_raw, where Z is the current zone.
|
||||
|
||||
What: /sys/bus/iio/devices/iio:deviceX/out_currentY_currentZ_raw
|
||||
Date: May 2012
|
||||
KernelVersion: 3.5
|
||||
@ -59,3 +51,6 @@ Description:
|
||||
|
||||
These values correspond to the ALS-mapper target registers for
|
||||
ALS-mapper Y + 1.
|
||||
|
||||
Note that out_currentY_raw provides the current for the
|
||||
current zone.
|
||||
|
@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/adi,adis16201.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ADIS16201 Dual Axis Inclinometer and similar
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <Jonathan.Cameron@huawei.com>
|
||||
|
||||
description: |
|
||||
Two similar parts from external interface point of view.
|
||||
SPI interface.
|
||||
https://www.analog.com/en/products/adis16201.html
|
||||
https://www.analog.com/en/products/adis16209.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,adis16201
|
||||
- adi,adis16209
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
accelerometer@0 {
|
||||
compatible = "adi,adis16201";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <2500000>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
@ -4,7 +4,7 @@
|
||||
$id: http://devicetree.org/schemas/iio/accel/bosch,bma180.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Bosch BMA023 / BMA150/ BMA180 / BMA25x / SMB380 triaxial accelerometers
|
||||
title: Bosch BMA023 / BMA150/ BMA180 / BMA250 / SMB380 triaxial accelerometers
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
@ -21,7 +21,6 @@ properties:
|
||||
- bosch,bma150
|
||||
- bosch,bma180
|
||||
- bosch,bma250
|
||||
- bosch,bma254
|
||||
- bosch,smb380
|
||||
|
||||
reg:
|
||||
|
@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/bosch,bma220.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Bosch BMA220 Trixial Acceleration Sensor
|
||||
|
||||
maintainers:
|
||||
- Jonathan Cameron <Jonathan.Cameron@huawei.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- bosch,bma220
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
vdda-supply: true
|
||||
vddd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
accelerometer@0 {
|
||||
compatible = "bosch,bma220";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <2500000>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
@ -18,6 +18,8 @@ properties:
|
||||
enum:
|
||||
- bosch,bmc150_accel
|
||||
- bosch,bmi055_accel
|
||||
- bosch,bma253
|
||||
- bosch,bma254
|
||||
- bosch,bma255
|
||||
- bosch,bma250e
|
||||
- bosch,bma222
|
||||
@ -31,7 +33,12 @@ properties:
|
||||
vddio-supply: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
description: |
|
||||
The first interrupt listed must be the one connected to the INT1 pin,
|
||||
the second (optional) interrupt listed must be the one connected to the
|
||||
INT2 pin (if available).
|
||||
|
||||
mount-matrix:
|
||||
description: an optional 3x3 mounting rotation matrix.
|
||||
|
82
Documentation/devicetree/bindings/iio/accel/fsl,mma7455.yaml
Normal file
82
Documentation/devicetree/bindings/iio/accel/fsl,mma7455.yaml
Normal file
@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/fsl,mma7455.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale MMA7455 and MMA7456 three axis accelerometers
|
||||
|
||||
maintainers:
|
||||
- Joachim Eastwood <manabian@gmail.com>
|
||||
- Jonathan Cameron <jic23@kernel.org>
|
||||
|
||||
description:
|
||||
Devices support both SPI and I2C interfaces.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,mma7455
|
||||
- fsl,mma7456
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
avdd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
description:
|
||||
Data ready is only available on INT1, but events can use either or
|
||||
both pins. If not specified, first element assumed to correspond
|
||||
to INT1 and second (where present) to INT2.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
enum:
|
||||
- "INT1"
|
||||
- "INT2"
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
# include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
accelerometer@18 {
|
||||
compatible = "fsl,mma7455";
|
||||
reg = <0x18>;
|
||||
vddio-supply = <&iovdd>;
|
||||
avdd-supply = <&avdd>;
|
||||
interrupts = <57 IRQ_TYPE_EDGE_FALLING>, <58 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-names = "INT2", "INT1";
|
||||
};
|
||||
};
|
||||
- |
|
||||
# include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
accelerometer@0 {
|
||||
compatible = "fsl,mma7456";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <10000000>;
|
||||
vddio-supply = <&iovdd>;
|
||||
avdd-supply = <&avdd>;
|
||||
interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
||||
...
|
@ -16,6 +16,7 @@ properties:
|
||||
- kionix,kxcj91008
|
||||
- kionix,kxtj21009
|
||||
- kionix,kxtf9
|
||||
- kionix,kx023-1025
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/murata,sca3300.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Murata SCA3300 Accelerometer
|
||||
|
||||
description: |
|
||||
3-axis industrial accelerometer with digital SPI interface
|
||||
https://www.murata.com/en-global/products/sensor/accel/sca3300
|
||||
|
||||
maintainers:
|
||||
- Tomas Melin <tomas.melin@vaisala.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- murata,sca3300
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 8000000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
accelerometer@0 {
|
||||
compatible = "murata,sca3300";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <4000000>;
|
||||
};
|
||||
};
|
||||
...
|
@ -0,0 +1,80 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/accel/nxp,fxls8962af.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP FXLS8962AF/FXLS8964AF Accelerometer driver
|
||||
|
||||
maintainers:
|
||||
- Sean Nyekjaer <sean@geanix.com>
|
||||
|
||||
description: |
|
||||
NXP FXLS8962AF/FXLS8964AF Accelerometer driver that supports
|
||||
SPI and I2C interface.
|
||||
https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,fxls8962af
|
||||
- nxp,fxls8964af
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply:
|
||||
description: phandle to the regulator that provides power to the accelerometer
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-names:
|
||||
enum:
|
||||
- INT1
|
||||
- INT2
|
||||
|
||||
drive-open-drain:
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* Example for a I2C device node */
|
||||
accelerometer@62 {
|
||||
compatible = "nxp,fxls8962af";
|
||||
reg = <0x62>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
/* Example for a SPI device node */
|
||||
accelerometer@0 {
|
||||
compatible = "nxp,fxls8962af";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <4000000>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "INT1";
|
||||
};
|
||||
};
|
@ -39,4 +39,16 @@ properties:
|
||||
The first value specifies the positive input pin, the second
|
||||
specifies the negative input pin.
|
||||
|
||||
settling-time-us:
|
||||
description:
|
||||
Time between enabling the channel and first stable readings.
|
||||
|
||||
oversampling-ratio:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Oversampling is used as replacement of or addition to the low-pass filter.
|
||||
In some cases, the desired filtering characteristics are a function the
|
||||
device design and can interact with other characteristics such as
|
||||
settling time.
|
||||
|
||||
additionalProperties: true
|
||||
|
48
Documentation/devicetree/bindings/iio/adc/adi,ad7298.yaml
Normal file
48
Documentation/devicetree/bindings/iio/adc/adi,ad7298.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2019 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad7298.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD7298 ADC
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
Bindings for the Analog Devices AD7298 ADC device. Datasheet can be
|
||||
found here:
|
||||
https://www.analog.com/en/products/ad7298.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,ad7298
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vref-supply: true
|
||||
vdd-supply: true
|
||||
spi-max-frequency: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad7298";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <5000000>;
|
||||
vref-supply = <&adc_vref>;
|
||||
};
|
||||
};
|
||||
...
|
174
Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml
Normal file
174
Documentation/devicetree/bindings/iio/adc/adi,ad7476.yaml
Normal file
@ -0,0 +1,174 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2019 Analog Devices Inc.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/adi,ad7476.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: AD7476 and similar simple SPI ADCs from multiple manufacturers.
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
A lot of simple SPI ADCs have very straight forward interfaces.
|
||||
They typically don't provide a MOSI pin, simply reading out data
|
||||
on MISO when the clock toggles.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad7091
|
||||
- adi,ad7091r
|
||||
- adi,ad7273
|
||||
- adi,ad7274
|
||||
- adi,ad7276
|
||||
- adi,ad7277
|
||||
- adi,ad7278
|
||||
- adi,ad7466
|
||||
- adi,ad7467
|
||||
- adi,ad7468
|
||||
- adi,ad7475
|
||||
- adi,ad7476
|
||||
- adi,ad7476a
|
||||
- adi,ad7477
|
||||
- adi,ad7477a
|
||||
- adi,ad7478
|
||||
- adi,ad7478a
|
||||
- adi,ad7495
|
||||
- adi,ad7910
|
||||
- adi,ad7920
|
||||
- adi,ad7940
|
||||
- ti,adc081s
|
||||
- ti,adc101s
|
||||
- ti,adc121s
|
||||
- ti,ads7866
|
||||
- ti,ads7867
|
||||
- ti,ads7868
|
||||
- lltc,ltc2314-14
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply:
|
||||
description:
|
||||
Main powersupply voltage for the chips, sometimes referred to as VDD on
|
||||
datasheets. If there is no separate vref-supply, then this is needed
|
||||
to establish channel scaling.
|
||||
|
||||
vdrive-supply:
|
||||
description:
|
||||
Some devices have separate supply for their digital control side.
|
||||
|
||||
vref-supply:
|
||||
description:
|
||||
Some devices have a specific reference voltage supplied on a different pin
|
||||
to the other supplies. Needed to be able to establish channel scaling
|
||||
unless there is also an internal reference available (e.g. ad7091r)
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
adi,conversion-start-gpios:
|
||||
description: A GPIO used to trigger the start of a conversion
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
# Devices where reference is vcc
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7091
|
||||
- adi,ad7276
|
||||
- adi,ad7277
|
||||
- adi,ad7278
|
||||
- adi,ad7466
|
||||
- adi,ad7467
|
||||
- adi,ad7468
|
||||
- adi,ad7940
|
||||
- ti,adc081s
|
||||
- ti,adc101s
|
||||
- ti,adc121s
|
||||
- ti,ads7866
|
||||
- ti,ads7868
|
||||
required:
|
||||
- vcc-supply
|
||||
# Devices with a vref
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7091r
|
||||
- adi,ad7273
|
||||
- adi,ad7274
|
||||
- adi,ad7475
|
||||
- lltc,ltc2314-14
|
||||
then:
|
||||
properties:
|
||||
vref-supply: true
|
||||
else:
|
||||
properties:
|
||||
vref-supply: false
|
||||
# Devices with a vref where it is not optional
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7273
|
||||
- adi,ad7274
|
||||
- adi,ad7475
|
||||
- lltc,ltc2314-14
|
||||
then:
|
||||
required:
|
||||
- vref-supply
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7475
|
||||
- adi,ad7495
|
||||
then:
|
||||
properties:
|
||||
vdrive-supply: true
|
||||
else:
|
||||
properties:
|
||||
vdrive-supply: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- adi,ad7091
|
||||
- adi,ad7091r
|
||||
then:
|
||||
properties:
|
||||
adi,conversion-start-gpios: true
|
||||
else:
|
||||
properties:
|
||||
adi,conversion-start-gpios: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "adi,ad7091r";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <5000000>;
|
||||
vcc-supply = <&adc_vcc>;
|
||||
vref-supply = <&adc_vref>;
|
||||
};
|
||||
};
|
||||
...
|
115
Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml
Normal file
115
Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml
Normal file
@ -0,0 +1,115 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/ti,tsc2046.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments TSC2046 touch screen controller.
|
||||
|
||||
maintainers:
|
||||
- Oleksij Rempel <o.rempel@pengutronix.de>
|
||||
|
||||
description: |
|
||||
TSC2046 is a touch screen controller with 8 channels ADC.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,tsc2046e-adc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-7]$":
|
||||
$ref: "adc.yaml"
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: |
|
||||
The channel number. It can have up to 8 channels
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
|
||||
settling-time-us: true
|
||||
oversampling-ratio: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adc@0 {
|
||||
compatible = "ti,tsc2046e-adc";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
interrupts-extended = <&gpio3 20 IRQ_TYPE_LEVEL_LOW>;
|
||||
#io-channel-cells = <1>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
settling-time-us = <700>;
|
||||
oversampling-ratio = <5>;
|
||||
};
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
};
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
settling-time-us = <700>;
|
||||
oversampling-ratio = <5>;
|
||||
};
|
||||
channel@4 {
|
||||
reg = <4>;
|
||||
settling-time-us = <700>;
|
||||
oversampling-ratio = <5>;
|
||||
};
|
||||
channel@5 {
|
||||
reg = <5>;
|
||||
settling-time-us = <700>;
|
||||
oversampling-ratio = <5>;
|
||||
};
|
||||
channel@6 {
|
||||
reg = <6>;
|
||||
};
|
||||
channel@7 {
|
||||
reg = <7>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
@ -24,6 +24,9 @@ properties:
|
||||
description: |
|
||||
Channel node of a voltage io-channel.
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 0
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description: The shunt resistance.
|
||||
|
||||
@ -57,6 +60,7 @@ examples:
|
||||
sysi {
|
||||
compatible = "current-sense-shunt";
|
||||
io-channels = <&tiadc 0>;
|
||||
#io-channel-cells = <0>;
|
||||
|
||||
/* Divide the voltage by 3300000/1000000 (or 3.3) for the current. */
|
||||
shunt-resistor-micro-ohms = <3300000>;
|
||||
|
77
Documentation/devicetree/bindings/iio/cdc/adi,ad7746.yaml
Normal file
77
Documentation/devicetree/bindings/iio/cdc/adi,ad7746.yaml
Normal file
@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/cdc/adi,ad7746.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: AD7746 24-Bit Capacitance-to-Digital Converter with Temperature Sensor
|
||||
|
||||
maintainers:
|
||||
- Michael Hennerich <michael.hennerich@analog.com>
|
||||
|
||||
description: |
|
||||
AD7746 24-Bit Capacitance-to-Digital Converter with Temperature Sensor
|
||||
|
||||
Specifications about the part can be found at:
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7291.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad7745
|
||||
- adi,ad7746
|
||||
- adi,ad7747
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
adi,excitation-vdd-permille:
|
||||
description: |
|
||||
Set VDD per mille to be used as the excitation voltage.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [125, 250, 375, 500]
|
||||
|
||||
adi,exca-output-en:
|
||||
description: Enables the EXCA pin as the excitation output.
|
||||
type: boolean
|
||||
|
||||
adi,exca-output-invert:
|
||||
description: |
|
||||
Inverts the excitation output in the EXCA pin.
|
||||
Normally only one of the EXCX pins would be inverted, check the following
|
||||
application notes for more details
|
||||
https://www.analog.com/media/en/technical-documentation/application-notes/AN-1585.pdf
|
||||
type: boolean
|
||||
|
||||
adi,excb-output-en:
|
||||
description: Enables the EXCB pin as the excitation output.
|
||||
type: boolean
|
||||
|
||||
adi,excb-output-invert:
|
||||
description: Inverts the excitation output in the EXCB pin.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ad7746: cdc@48 {
|
||||
compatible = "adi,ad7746";
|
||||
reg = <0x48>;
|
||||
adi,excitation-vdd-permille = <125>;
|
||||
|
||||
adi,exca-output-en;
|
||||
adi,exca-output-invert;
|
||||
adi,excb-output-en;
|
||||
adi,excb-output-invert;
|
||||
};
|
||||
};
|
||||
...
|
@ -22,7 +22,6 @@ properties:
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -37,5 +36,11 @@ examples:
|
||||
reg = <0x69>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
serial {
|
||||
air-pollution-sensor {
|
||||
compatible = "sensirion,sps30";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
@ -1,124 +0,0 @@
|
||||
* Analog Devices AD5755 IIO Multi-Channel DAC Linux Driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Has to contain one of the following:
|
||||
adi,ad5755
|
||||
adi,ad5755-1
|
||||
adi,ad5757
|
||||
adi,ad5735
|
||||
adi,ad5737
|
||||
|
||||
- reg: spi chip select number for the device
|
||||
- spi-cpha or spi-cpol: is the only modes that is supported
|
||||
|
||||
Recommended properties:
|
||||
- spi-max-frequency: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Optional properties:
|
||||
See include/dt-bindings/iio/ad5755.h
|
||||
- adi,ext-dc-dc-compenstation-resistor: boolean set if the hardware have an
|
||||
external resistor and thereby bypasses
|
||||
the internal compensation resistor.
|
||||
- adi,dc-dc-phase:
|
||||
Valid values for DC DC Phase control is:
|
||||
0: All dc-to-dc converters clock on the same edge.
|
||||
1: Channel A and Channel B clock on the same edge,
|
||||
Channel C and Channel D clock on opposite edges.
|
||||
2: Channel A and Channel C clock on the same edge,
|
||||
Channel B and Channel D clock on opposite edges.
|
||||
3: Channel A, Channel B, Channel C, and Channel D
|
||||
clock 90 degrees out of phase from each other.
|
||||
- adi,dc-dc-freq-hz:
|
||||
Valid values for DC DC frequency is [Hz]:
|
||||
250000
|
||||
410000
|
||||
650000
|
||||
- adi,dc-dc-max-microvolt:
|
||||
Valid values for the maximum allowed Vboost voltage supplied by
|
||||
the dc-to-dc converter is:
|
||||
23000000
|
||||
24500000
|
||||
27000000
|
||||
29500000
|
||||
|
||||
Optional for every channel:
|
||||
- adi,mode:
|
||||
Valid values for DAC modes is:
|
||||
0: 0 V to 5 V voltage range.
|
||||
1: 0 V to 10 V voltage range.
|
||||
2: Plus minus 5 V voltage range.
|
||||
3: Plus minus 10 V voltage range.
|
||||
4: 4 mA to 20 mA current range.
|
||||
5: 0 mA to 20 mA current range.
|
||||
6: 0 mA to 24 mA current range.
|
||||
- adi,ext-current-sense-resistor: boolean set if the hardware a external
|
||||
current sense resistor.
|
||||
- adi,enable-voltage-overrange: boolean enable voltage overrange
|
||||
- adi,slew: Array of slewrate settings should contain 3 fields:
|
||||
1: Should be either 0 or 1 in order to enable or disable slewrate.
|
||||
2: Slew rate settings:
|
||||
Valid values for the slew rate update frequency:
|
||||
64000
|
||||
32000
|
||||
16000
|
||||
8000
|
||||
4000
|
||||
2000
|
||||
1000
|
||||
500
|
||||
250
|
||||
125
|
||||
64
|
||||
32
|
||||
16
|
||||
8
|
||||
4
|
||||
0
|
||||
3: Slew step size:
|
||||
Valid values for the step size LSBs:
|
||||
1
|
||||
2
|
||||
4
|
||||
16
|
||||
32
|
||||
64
|
||||
128
|
||||
256
|
||||
|
||||
Example:
|
||||
dac@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "adi,ad5755";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
spi-cpha;
|
||||
adi,dc-dc-phase = <0>;
|
||||
adi,dc-dc-freq-hz = <410000>;
|
||||
adi,dc-dc-max-microvolt = <23000000>;
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
};
|
169
Documentation/devicetree/bindings/iio/dac/adi,ad5755.yaml
Normal file
169
Documentation/devicetree/bindings/iio/dac/adi,ad5755.yaml
Normal file
@ -0,0 +1,169 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/adi,ad5755.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices AD5755 Multi-Channel DAC
|
||||
|
||||
maintainers:
|
||||
- Sean Nyekjaer <sean.nyekjaer@prevas.dk>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ad5755
|
||||
- adi,ad5755-1
|
||||
- adi,ad5757
|
||||
- adi,ad5735
|
||||
- adi,ad5737
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-cpha:
|
||||
description: Either this or spi-cpol but not both.
|
||||
spi-cpol: true
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
adi,ext-dc-dc-compenstation-resistor:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Set if the hardware have an external resistor and thereby bypasses
|
||||
the internal compensation resistor.
|
||||
|
||||
adi,dc-dc-phase:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3]
|
||||
description: |
|
||||
Valid values for DC DC Phase control is:
|
||||
0: All dc-to-dc converters clock on the same edge.
|
||||
1: Channel A and Channel B clock on the same edge,
|
||||
Channel C and Channel D clock on opposite edges.
|
||||
2: Channel A and Channel C clock on the same edge,
|
||||
Channel B and Channel D clock on opposite edges.
|
||||
3: Channel A, Channel B, Channel C, and Channel D
|
||||
clock 90 degrees out of phase from each other.
|
||||
|
||||
adi,dc-dc-freq-hz:
|
||||
enum: [250000, 410000, 650000]
|
||||
|
||||
adi,dc-dc-max-microvolt:
|
||||
description:
|
||||
Maximum allowed Vboost voltage supplied by the dc-to-dc converter.
|
||||
enum: [23000000, 24500000, 27000000, 29500000]
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
"#io-channel-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-7]$":
|
||||
type: object
|
||||
description: Child node to describe a channel
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
adi,mode:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 6
|
||||
description: |
|
||||
Valid values for DAC modes is:
|
||||
0: 0 V to 5 V voltage range.
|
||||
1: 0 V to 10 V voltage range.
|
||||
2: Plus minus 5 V voltage range.
|
||||
3: Plus minus 10 V voltage range.
|
||||
4: 4 mA to 20 mA current range.
|
||||
5: 0 mA to 20 mA current range.
|
||||
6: 0 mA to 24 mA current range.
|
||||
|
||||
adi,ext-current-sense-resistor:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Set if the hardware has an external current sense resistor
|
||||
|
||||
adi,enable-voltage-overrange:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description: Enable voltage overrange
|
||||
|
||||
adi,slew:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description: |
|
||||
Array of slewrate settings should contain 3 fields:
|
||||
1: Should be either 0 or 1 in order to enable or disable slewrate.
|
||||
2: Slew rate update frequency
|
||||
3: Slew step size
|
||||
items:
|
||||
- enum: [0, 1]
|
||||
- enum: [64000, 32000, 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 64, 32, 16, 8, 4, 0]
|
||||
- enum: [1, 2, 4, 16, 32, 64, 128, 256]
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
oneOf:
|
||||
- required:
|
||||
- spi-cpha
|
||||
- required:
|
||||
- spi-cpol
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/iio/adi,ad5592r.h>
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "adi,ad5755";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
spi-cpha;
|
||||
adi,dc-dc-phase = <0>;
|
||||
adi,dc-dc-freq-hz = <410000>;
|
||||
adi,dc-dc-max-microvolt = <23000000>;
|
||||
channel@0 {
|
||||
reg = <0>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
channel@1 {
|
||||
reg = <1>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
channel@2 {
|
||||
reg = <2>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
channel@3 {
|
||||
reg = <3>;
|
||||
adi,mode = <4>;
|
||||
adi,ext-current-sense-resistor;
|
||||
adi,slew = <0 64000 1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
72
Documentation/devicetree/bindings/iio/dac/ti,dac082s085.yaml
Normal file
72
Documentation/devicetree/bindings/iio/dac/ti,dac082s085.yaml
Normal file
@ -0,0 +1,72 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/dac/ti,dac082s085.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments DAC082s085 and similar DACs
|
||||
|
||||
description:
|
||||
A family of Texas Instruments 8/10/12-bit 2/4-channel DACs
|
||||
|
||||
maintainers:
|
||||
- Lukas Wunner <lukas@wunner.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,dac082s085
|
||||
- ti,dac102s085
|
||||
- ti,dac122s085
|
||||
- ti,dac084s085
|
||||
- ti,dac104s085
|
||||
- ti,dac124s085
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spi-cpha: true
|
||||
spi-cpol:
|
||||
description:
|
||||
Must be either spi-cpha, or spi-cpol but not both.
|
||||
|
||||
vref-supply:
|
||||
description: Needed to provide output scaling.
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vref-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
oneOf:
|
||||
- required:
|
||||
- spi-cpha
|
||||
- required:
|
||||
- spi-cpol
|
||||
|
||||
examples:
|
||||
- |
|
||||
vref_2v5_reg: regulator-vref {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "2v5";
|
||||
regulator-min-microvolt = <2500000>;
|
||||
regulator-max-microvolt = <2500000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
dac@0 {
|
||||
compatible = "ti,dac082s085";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
spi-cpol;
|
||||
vref-supply = <&vref_2v5_reg>;
|
||||
};
|
||||
};
|
||||
...
|
@ -1,34 +0,0 @@
|
||||
Texas Instruments 8/10/12-bit 2/4-channel DAC driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of:
|
||||
"ti,dac082s085"
|
||||
"ti,dac102s085"
|
||||
"ti,dac122s085"
|
||||
"ti,dac084s085"
|
||||
"ti,dac104s085"
|
||||
"ti,dac124s085"
|
||||
- reg: Chip select number.
|
||||
- spi-cpha, spi-cpol: SPI mode (0,1) or (1,0) must be used, so specify
|
||||
either spi-cpha or spi-cpol (but not both).
|
||||
- vref-supply: Phandle to the external reference voltage supply.
|
||||
|
||||
For other required and optional properties of SPI slave nodes please refer to
|
||||
../../spi/spi-bus.txt.
|
||||
|
||||
Example:
|
||||
vref_2v5_reg: regulator-vref {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "2v5";
|
||||
regulator-min-microvolt = <2500000>;
|
||||
regulator-max-microvolt = <2500000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
dac@0 {
|
||||
compatible = "ti,dac082s085";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
spi-cpol;
|
||||
vref-supply = <&vref_2v5_reg>;
|
||||
};
|
@ -0,0 +1,50 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/light/amstaos,tsl2591.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: AMS/TAOS TSL2591 Ambient Light Sensor (ALS)
|
||||
|
||||
maintainers:
|
||||
- Joe Sandom <joe.g.sandom@gmail.com>
|
||||
|
||||
description: |
|
||||
AMS/TAOS TSL2591 is a very-high sensitivity
|
||||
light-to-digital converter that transforms light intensity into a digital
|
||||
signal.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: amstaos,tsl2591
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description:
|
||||
Interrupt (INT:Pin 2) Active low. Should be set to IRQ_TYPE_EDGE_FALLING.
|
||||
interrupt is used to detect if the light intensity has fallen below
|
||||
or reached above the configured threshold values.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tsl2591@29 {
|
||||
compatible = "amstaos,tsl2591";
|
||||
reg = <0x29>;
|
||||
interrupts = <20 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
...
|
@ -6,7 +6,9 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics MEMS sensors
|
||||
|
||||
description: |
|
||||
description: The STMicroelectronics sensor devices are pretty straight-forward
|
||||
I2C or SPI devices, all sharing the same device tree descriptions no matter
|
||||
what type of sensor it is.
|
||||
Note that whilst this covers many STMicro MEMs sensors, some more complex
|
||||
IMUs need their own bindings.
|
||||
The STMicroelectronics sensor devices are pretty straight-forward I2C or
|
||||
@ -15,90 +17,181 @@ description: |
|
||||
|
||||
maintainers:
|
||||
- Denis Ciocca <denis.ciocca@st.com>
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
description: |
|
||||
Some values are deprecated.
|
||||
st,lis3lv02d (deprecated, use st,lis3lv02dl-accel)
|
||||
st,lis302dl-spi (deprecated, use st,lis3lv02dl-accel)
|
||||
enum:
|
||||
# Accelerometers
|
||||
- st,lis3lv02d
|
||||
- st,lis302dl-spi
|
||||
- st,lis3lv02dl-accel
|
||||
- st,lsm303dlh-accel
|
||||
- st,lsm303dlhc-accel
|
||||
- st,lis3dh-accel
|
||||
- st,lsm330d-accel
|
||||
- st,lsm330dl-accel
|
||||
- st,lsm330dlc-accel
|
||||
- st,lis331dl-accel
|
||||
- st,lis331dlh-accel
|
||||
- st,lsm303dl-accel
|
||||
- st,lsm303dlm-accel
|
||||
- st,lsm330-accel
|
||||
- st,lsm303agr-accel
|
||||
- st,lis2dh12-accel
|
||||
- st,h3lis331dl-accel
|
||||
- st,lng2dm-accel
|
||||
- st,lis3l02dq
|
||||
- st,lis2dw12
|
||||
- st,lis3dhh
|
||||
- st,lis3de
|
||||
- st,lis2de12
|
||||
- st,lis2hh12
|
||||
# Gyroscopes
|
||||
- st,l3g4200d-gyro
|
||||
- st,lsm330d-gyro
|
||||
- st,lsm330dl-gyro
|
||||
- st,lsm330dlc-gyro
|
||||
- st,l3gd20-gyro
|
||||
- st,l3gd20h-gyro
|
||||
- st,l3g4is-gyro
|
||||
- st,lsm330-gyro
|
||||
- st,lsm9ds0-gyro
|
||||
# Magnetometers
|
||||
- st,lsm303agr-magn
|
||||
- st,lsm303dlh-magn
|
||||
- st,lsm303dlhc-magn
|
||||
- st,lsm303dlm-magn
|
||||
- st,lis3mdl-magn
|
||||
- st,lis2mdl
|
||||
- st,lsm9ds1-magn
|
||||
- st,iis2mdc
|
||||
# Pressure sensors
|
||||
- st,lps001wp-press
|
||||
- st,lps25h-press
|
||||
- st,lps331ap-press
|
||||
- st,lps22hb-press
|
||||
- st,lps33hw
|
||||
- st,lps35hw
|
||||
- st,lps22hh
|
||||
oneOf:
|
||||
- description: STMicroelectronics Accelerometers
|
||||
enum:
|
||||
- st,h3lis331dl-accel
|
||||
- st,lis2de12
|
||||
- st,lis2dw12
|
||||
- st,lis2hh12
|
||||
- st,lis2dh12-accel
|
||||
- st,lis331dl-accel
|
||||
- st,lis331dlh-accel
|
||||
- st,lis3de
|
||||
- st,lis3dh-accel
|
||||
- st,lis3dhh
|
||||
- st,lis3l02dq
|
||||
- st,lis3lv02dl-accel
|
||||
- st,lng2dm-accel
|
||||
- st,lsm303agr-accel
|
||||
- st,lsm303dl-accel
|
||||
- st,lsm303dlh-accel
|
||||
- st,lsm303dlhc-accel
|
||||
- st,lsm303dlm-accel
|
||||
- st,lsm330-accel
|
||||
- st,lsm330d-accel
|
||||
- st,lsm330dl-accel
|
||||
- st,lsm330dlc-accel
|
||||
- description: STMicroelectronics Gyroscopes
|
||||
enum:
|
||||
- st,l3g4200d-gyro
|
||||
- st,l3g4is-gyro
|
||||
- st,l3gd20-gyro
|
||||
- st,l3gd20h-gyro
|
||||
- st,lsm330-gyro
|
||||
- st,lsm330d-gyro
|
||||
- st,lsm330dl-gyro
|
||||
- st,lsm330dlc-gyro
|
||||
- st,lsm9ds0-gyro
|
||||
- description: STMicroelectronics Magnetometers
|
||||
enum:
|
||||
- st,lis2mdl
|
||||
- st,lis3mdl-magn
|
||||
- st,lsm303agr-magn
|
||||
- st,lsm303dlh-magn
|
||||
- st,lsm303dlhc-magn
|
||||
- st,lsm303dlm-magn
|
||||
- st,lsm9ds1-magn
|
||||
- description: STMicroelectronics Pressure Sensors
|
||||
enum:
|
||||
- st,lps001wp-press
|
||||
- st,lps22hb-press
|
||||
- st,lps22hh
|
||||
- st,lps25h-press
|
||||
- st,lps331ap-press
|
||||
- st,lps33hw
|
||||
- st,lps35hw
|
||||
- description: IMUs
|
||||
enum:
|
||||
- st,lsm9ds0-imu
|
||||
- description: Deprecated bindings
|
||||
enum:
|
||||
- st,lis302dl-spi
|
||||
- st,lis3lv02d
|
||||
deprecated: true
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: interrupt line(s) connected to the DRDY line(s) and/or the
|
||||
Intertial interrupt lines INT1 and INT2 if these exist. This means up to
|
||||
three interrupts, and the DRDY must be the first one if it exists on
|
||||
the package. The trigger edge of the interrupts is sometimes software
|
||||
configurable in the hardware so the operating system should parse this
|
||||
flag and set up the trigger edge as indicated in the device tree.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
vdd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
st,drdy-int-pin:
|
||||
description: the pin on the package that will be used to signal
|
||||
"data ready" (valid values 1 or 2). This property is not configurable
|
||||
on all sensors.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Some sensors have multiple possible pins via which they can provide
|
||||
a data ready interrupt. This selects which one.
|
||||
enum:
|
||||
- 1
|
||||
- 2
|
||||
enum: [1, 2]
|
||||
|
||||
drive-open-drain:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description: |
|
||||
The interrupt/data ready line will be configured as open drain, which
|
||||
is useful if several sensors share the same interrupt line.
|
||||
description: the interrupt/data ready line will be configured
|
||||
as open drain, which is useful if several sensors share the same
|
||||
interrupt line. (This binding is taken from pinctrl.)
|
||||
|
||||
mount-matrix:
|
||||
description: an optional 3x3 mounting rotation matrix.
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# These have no interrupts
|
||||
- st,lps001wp
|
||||
then:
|
||||
properties:
|
||||
interrupts: false
|
||||
st,drdy-int-pin: false
|
||||
drive-open-drain: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# These have only DRDY
|
||||
- st,lis2mdl
|
||||
- st,lis3l02dq
|
||||
- st,lis3lv02dl-accel
|
||||
- st,lps22hb-press
|
||||
- st,lps22hh
|
||||
- st,lps25h-press
|
||||
- st,lps33hw
|
||||
- st,lps35hw
|
||||
- st,lsm303agr-magn
|
||||
- st,lsm303dlh-magn
|
||||
- st,lsm303dlhc-magn
|
||||
- st,lsm303dlm-magn
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
st,drdy-int-pin: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# Two intertial interrupts i.e. accelerometer/gyro interrupts
|
||||
- st,h3lis331dl-accel
|
||||
- st,l3g4200d-gyro
|
||||
- st,l3g4is-gyro
|
||||
- st,l3gd20-gyro
|
||||
- st,l3gd20h-gyro
|
||||
- st,lis2de12
|
||||
- st,lis2dw12
|
||||
- st,lis2hh12
|
||||
- st,lis2dh12-accel
|
||||
- st,lis331dl-accel
|
||||
- st,lis331dlh-accel
|
||||
- st,lis3de
|
||||
- st,lis3dh-accel
|
||||
- st,lis3dhh
|
||||
- st,lis3mdl-magn
|
||||
- st,lng2dm-accel
|
||||
- st,lps331ap-press
|
||||
- st,lsm303agr-accel
|
||||
- st,lsm303dlh-accel
|
||||
- st,lsm303dlhc-accel
|
||||
- st,lsm303dlm-accel
|
||||
- st,lsm330-accel
|
||||
- st,lsm330-gyro
|
||||
- st,lsm330d-accel
|
||||
- st,lsm330d-gyro
|
||||
- st,lsm330dl-accel
|
||||
- st,lsm330dl-gyro
|
||||
- st,lsm330dlc-accel
|
||||
- st,lsm330dlc-gyro
|
||||
- st,lsm9ds0-gyro
|
||||
- st,lsm9ds1-magn
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@ -110,15 +203,30 @@ examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
accelerometer@1d {
|
||||
compatible = "st,lis3lv02dl-accel";
|
||||
reg = <0x1d>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <18 IRQ_TYPE_EDGE_RISING>;
|
||||
pinctrl-0 = <&lis3lv02dl_nhk_mode>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
accelerometer@1c {
|
||||
compatible = "st,lis331dl-accel";
|
||||
reg = <0x1c>;
|
||||
st,drdy-int-pin = <1>;
|
||||
vdd-supply = <&ldo1>;
|
||||
vddio-supply = <&ldo2>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <18 IRQ_TYPE_EDGE_RISING>, <19 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
};
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
num-cs = <1>;
|
||||
|
||||
l3g4200d: gyroscope@0 {
|
||||
compatible = "st,l3g4200d-gyro";
|
||||
st,drdy-int-pin = <2>;
|
||||
reg = <0>;
|
||||
vdd-supply = <&vcc_io>;
|
||||
vddio-supply = <&vcc_io>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -0,0 +1,41 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/iio/temperature/ti,tmp117.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: "TI TMP117 - Digital temperature sensor with integrated NV memory"
|
||||
|
||||
description: |
|
||||
TI TMP117 - Digital temperature sensor with integrated NV memory that supports
|
||||
I2C interface.
|
||||
https://www.ti.com/lit/gpn/tmp1
|
||||
|
||||
maintainers:
|
||||
- Puranjay Mohan <puranjay12@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,tmp117
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tmp117@48 {
|
||||
compatible = "ti,tmp117";
|
||||
reg = <0x48>;
|
||||
};
|
||||
};
|
@ -14,7 +14,7 @@ description: |
|
||||
It is a MIPI System Power Management (SPMI) controller.
|
||||
|
||||
The PMIC part is provided by
|
||||
drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml.
|
||||
./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml.
|
||||
|
||||
allOf:
|
||||
- $ref: spmi.yaml#
|
||||
@ -30,7 +30,7 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
spmi-channel:
|
||||
hisilicon,spmi-channel:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: |
|
||||
number of the Kirin 970 SPMI channel where the SPMI devices are connected.
|
||||
@ -38,10 +38,12 @@ properties:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- spmi-channel
|
||||
- hisilicon,spmi-channel
|
||||
|
||||
patternProperties:
|
||||
"@[0-9a-f]$":
|
||||
type: object
|
||||
|
||||
description: |
|
||||
PMIC properties, which are specific to the used SPMI PMIC device(s).
|
||||
When used in combination with HiSilicon 6421v600, the properties
|
||||
@ -61,7 +63,7 @@ examples:
|
||||
#address-cells = <2>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x0 0xfff24000 0x0 0x1000>;
|
||||
spmi-channel = <2>;
|
||||
hisilicon,spmi-channel = <2>;
|
||||
|
||||
pmic@0 {
|
||||
reg = <0 0>;
|
@ -177,8 +177,14 @@ properties:
|
||||
- meas,tsys01
|
||||
# MEMSIC magnetometer
|
||||
- memsic,mmc35240
|
||||
# MEMSIC 3-axis accelerometer
|
||||
- memsic,mx4005
|
||||
# MEMSIC 2-axis 8-bit digital accelerometer
|
||||
- memsic,mxc6225
|
||||
# MEMSIC 2-axis 8-bit digital accelerometer
|
||||
- memsic,mxc6255
|
||||
# MEMSIC 3-axis accelerometer
|
||||
- memsic,mxc6655
|
||||
# Microchip differential I2C ADC, 1 Channel, 18 bit
|
||||
- microchip,mcp3421
|
||||
# Microchip differential I2C ADC, 2 Channel, 18 bit
|
||||
@ -263,6 +269,10 @@ properties:
|
||||
- sensirion,sgpc3
|
||||
# Sensirion multi-pixel gas sensor with I2C interface
|
||||
- sensirion,sgp30
|
||||
# Sensortek 3 axis accelerometer
|
||||
- sensortek,stk8312
|
||||
# Sensortek 3 axis accelerometer
|
||||
- sensortek,stk8ba50
|
||||
# SGX Sensortech VZ89X Sensors
|
||||
- sgx,vz89x
|
||||
# Relative Humidity and Temperature Sensors
|
||||
|
@ -307,7 +307,7 @@ Determining the type of extension to create is a matter of scope.
|
||||
|
||||
* Device extensions are attributes that expose information/control
|
||||
non-specific to a particular Count or Signal. This is where you would
|
||||
put your global features or other miscellanous functionality.
|
||||
put your global features or other miscellaneous functionality.
|
||||
|
||||
For example, if your device has an overtemp sensor, you can report the
|
||||
chip overheated via a device extension called "error_overtemp":
|
||||
|
42
MAINTAINERS
42
MAINTAINERS
@ -299,7 +299,6 @@ M: William Breathitt Gray <vilhelm.gray@gmail.com>
|
||||
M: Syed Nayyar Waris <syednwaris@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-bus-counter-104-quad-8
|
||||
F: drivers/counter/104-quad-8.c
|
||||
|
||||
ACCES PCI-IDIO-16 GPIO DRIVER
|
||||
@ -4738,7 +4737,7 @@ COUNTER SUBSYSTEM
|
||||
M: William Breathitt Gray <vilhelm.gray@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-bus-counter*
|
||||
F: Documentation/ABI/testing/sysfs-bus-counter
|
||||
F: Documentation/driver-api/generic-counter.rst
|
||||
F: drivers/counter/
|
||||
F: include/linux/counter.h
|
||||
@ -7189,7 +7188,6 @@ FLEXTIMER FTM-QUADDEC DRIVER
|
||||
M: Patrick Havelange <patrick.havelange@essensium.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
|
||||
F: Documentation/devicetree/bindings/counter/ftm-quaddec.txt
|
||||
F: drivers/counter/ftm-quaddec.c
|
||||
|
||||
@ -8397,6 +8395,13 @@ S: Maintained
|
||||
W: http://www.hisilicon.com
|
||||
F: drivers/spi/spi-hisi-kunpeng.c
|
||||
|
||||
HISILICON SPMI CONTROLLER DRIVER FOR HIKEY 970
|
||||
M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
|
||||
F: drivers/spmi/hisi-spmi-controller.c
|
||||
|
||||
HISILICON STAGING DRIVERS FOR HIKEY 960/970
|
||||
M: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
|
||||
S: Maintained
|
||||
@ -9475,6 +9480,11 @@ L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/cpufreq/intel_pstate.c
|
||||
|
||||
INTEL QUADRATURE ENCODER PERIPHERAL DRIVER
|
||||
M: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
F: drivers/counter/intel-qep.c
|
||||
|
||||
INTEL SCU DRIVERS
|
||||
M: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
S: Maintained
|
||||
@ -16661,6 +16671,8 @@ M: Tomasz Duszynski <tduszyns@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/chemical/sensirion,sps30.yaml
|
||||
F: drivers/iio/chemical/sps30.c
|
||||
F: drivers/iio/chemical/sps30_i2c.c
|
||||
F: drivers/iio/chemical/sps30_serial.c
|
||||
|
||||
SERIAL DEVICE BUS
|
||||
M: Rob Herring <robh@kernel.org>
|
||||
@ -18285,6 +18297,13 @@ F: Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml
|
||||
F: Documentation/hwmon/tps23861.rst
|
||||
F: drivers/hwmon/tps23861.c
|
||||
|
||||
TEXAS INSTRUMENTS' TMP117 TEMPERATURE SENSOR DRIVER
|
||||
M: Puranjay Mohan <puranjay12@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/temperature/ti,tmp117.yaml
|
||||
F: drivers/iio/temperature/tmp117.c
|
||||
|
||||
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
|
||||
M: Hans Verkuil <hverkuil@xs4all.nl>
|
||||
L: linux-media@vger.kernel.org
|
||||
@ -18521,6 +18540,14 @@ S: Supported
|
||||
F: Documentation/devicetree/bindings/net/nfc/trf7970a.txt
|
||||
F: drivers/nfc/trf7970a.c
|
||||
|
||||
TI TSC2046 ADC DRIVER
|
||||
M: Oleksij Rempel <o.rempel@pengutronix.de>
|
||||
R: kernel@pengutronix.de
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/adc/ti,tsc2046.yaml
|
||||
F: drivers/iio/adc/ti-tsc2046.c
|
||||
|
||||
TI TWL4030 SERIES SOC CODEC DRIVER
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
@ -19037,7 +19064,7 @@ L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/usb/roles/intel-xhci-usb-role-switch.c
|
||||
|
||||
USB IP DRIVER FOR HISILICON KIRIN
|
||||
USB IP DRIVER FOR HISILICON KIRIN 960
|
||||
M: Yu Chen <chenyu56@huawei.com>
|
||||
M: Binghui Wang <wangbinghui@hisilicon.com>
|
||||
L: linux-usb@vger.kernel.org
|
||||
@ -19045,6 +19072,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
|
||||
F: drivers/phy/hisilicon/phy-hi3660-usb3.c
|
||||
|
||||
USB IP DRIVER FOR HISILICON KIRIN 970
|
||||
M: Mauro Carvalho Chehab <mchehab@kernel.org>
|
||||
L: linux-usb@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml
|
||||
F: drivers/phy/hisilicon/phy-kirin970-usb3.c
|
||||
|
||||
USB ISP116X DRIVER
|
||||
M: Olav Kongas <ok@artecdesign.ee>
|
||||
L: linux-usb@vger.kernel.org
|
||||
|
10
arch/mips/include/asm/mach-ralink/spaces.h
Normal file
10
arch/mips/include/asm/mach-ralink/spaces.h
Normal file
@ -0,0 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_MACH_RALINK_SPACES_H_
|
||||
#define __ASM_MACH_RALINK_SPACES_H_
|
||||
|
||||
#define PCI_IOBASE _AC(0xa0000000, UL)
|
||||
#define PCI_IOSIZE SZ_16M
|
||||
#define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
|
||||
|
||||
#include <asm/mach-generic/spaces.h>
|
||||
#endif
|
@ -186,19 +186,6 @@ static void set_full_scales(struct jr3_sensor __iomem *sensor,
|
||||
set_s16(&sensor->command_word0, 0x0a00);
|
||||
}
|
||||
|
||||
static struct six_axis_t get_min_full_scales(struct jr3_sensor __iomem *sensor)
|
||||
{
|
||||
struct six_axis_t result;
|
||||
|
||||
result.fx = get_s16(&sensor->min_full_scale.fx);
|
||||
result.fy = get_s16(&sensor->min_full_scale.fy);
|
||||
result.fz = get_s16(&sensor->min_full_scale.fz);
|
||||
result.mx = get_s16(&sensor->min_full_scale.mx);
|
||||
result.my = get_s16(&sensor->min_full_scale.my);
|
||||
result.mz = get_s16(&sensor->min_full_scale.mz);
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct six_axis_t get_max_full_scales(struct jr3_sensor __iomem *sensor)
|
||||
{
|
||||
struct six_axis_t result;
|
||||
@ -504,10 +491,8 @@ jr3_pci_poll_subdevice(struct comedi_subdevice *s)
|
||||
result = poll_delay_min_max(20, 100);
|
||||
} else {
|
||||
/* Set full scale */
|
||||
struct six_axis_t min_full_scale;
|
||||
struct six_axis_t max_full_scale;
|
||||
|
||||
min_full_scale = get_min_full_scales(sensor);
|
||||
max_full_scale = get_max_full_scales(sensor);
|
||||
set_full_scales(sensor, max_full_scale);
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)];
|
||||
static unsigned int num_quad8;
|
||||
module_param_array(base, uint, &num_quad8, 0);
|
||||
module_param_hw_array(base, uint, ioport, &num_quad8, 0);
|
||||
MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
|
||||
|
||||
#define QUAD8_NUM_COUNTERS 8
|
||||
@ -193,7 +193,7 @@ enum quad8_count_function {
|
||||
QUAD8_COUNT_FUNCTION_QUADRATURE_X4
|
||||
};
|
||||
|
||||
static enum counter_count_function quad8_count_functions_list[] = {
|
||||
static const enum counter_count_function quad8_count_functions_list[] = {
|
||||
[QUAD8_COUNT_FUNCTION_PULSE_DIRECTION] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A,
|
||||
[QUAD8_COUNT_FUNCTION_QUADRATURE_X2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
|
||||
@ -305,12 +305,12 @@ enum quad8_synapse_action {
|
||||
QUAD8_SYNAPSE_ACTION_BOTH_EDGES
|
||||
};
|
||||
|
||||
static enum counter_synapse_action quad8_index_actions_list[] = {
|
||||
static const enum counter_synapse_action quad8_index_actions_list[] = {
|
||||
[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
|
||||
[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE
|
||||
};
|
||||
|
||||
static enum counter_synapse_action quad8_synapse_actions_list[] = {
|
||||
static const enum counter_synapse_action quad8_synapse_actions_list[] = {
|
||||
[QUAD8_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
|
||||
[QUAD8_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
|
||||
[QUAD8_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
|
||||
@ -632,8 +632,8 @@ static ssize_t quad8_count_preset_read(struct counter_device *counter,
|
||||
return sprintf(buf, "%u\n", priv->preset[count->id]);
|
||||
}
|
||||
|
||||
static void quad8_preset_register_set(struct quad8 *priv, int id,
|
||||
unsigned int preset)
|
||||
static void quad8_preset_register_set(struct quad8 *const priv, const int id,
|
||||
const unsigned int preset)
|
||||
{
|
||||
const unsigned int base_offset = priv->base + 2 * id;
|
||||
int i;
|
||||
@ -1082,7 +1082,6 @@ static int quad8_probe(struct device *dev, unsigned int id)
|
||||
/* Enable all counters */
|
||||
outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
|
||||
|
||||
/* Register Counter device */
|
||||
return devm_counter_register(dev, &priv->counter);
|
||||
}
|
||||
|
||||
|
@ -91,4 +91,14 @@ config MICROCHIP_TCB_CAPTURE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called microchip-tcb-capture.
|
||||
|
||||
config INTEL_QEP
|
||||
tristate "Intel Quadrature Encoder Peripheral driver"
|
||||
depends on PCI
|
||||
help
|
||||
Select this option to enable the Intel Quadrature Encoder Peripheral
|
||||
driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called intel-qep.
|
||||
|
||||
endif # COUNTER
|
||||
|
@ -12,3 +12,4 @@ obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o
|
||||
obj-$(CONFIG_TI_EQEP) += ti-eqep.o
|
||||
obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o
|
||||
obj-$(CONFIG_MICROCHIP_TCB_CAPTURE) += microchip-tcb-capture.o
|
||||
obj-$(CONFIG_INTEL_QEP) += intel-qep.o
|
||||
|
@ -162,7 +162,7 @@ enum ftm_quaddec_synapse_action {
|
||||
FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES,
|
||||
};
|
||||
|
||||
static enum counter_synapse_action ftm_quaddec_synapse_actions[] = {
|
||||
static const enum counter_synapse_action ftm_quaddec_synapse_actions[] = {
|
||||
[FTM_QUADDEC_SYNAPSE_ACTION_BOTH_EDGES] =
|
||||
COUNTER_SYNAPSE_ACTION_BOTH_EDGES
|
||||
};
|
||||
|
544
drivers/counter/intel-qep.c
Normal file
544
drivers/counter/intel-qep.c
Normal file
@ -0,0 +1,544 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Intel Quadrature Encoder Peripheral driver
|
||||
*
|
||||
* Copyright (C) 2019-2021 Intel Corporation
|
||||
*
|
||||
* Author: Felipe Balbi (Intel)
|
||||
* Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
* Author: Raymond Tan <raymond.tan@intel.com>
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/counter.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define INTEL_QEPCON 0x00
|
||||
#define INTEL_QEPFLT 0x04
|
||||
#define INTEL_QEPCOUNT 0x08
|
||||
#define INTEL_QEPMAX 0x0c
|
||||
#define INTEL_QEPWDT 0x10
|
||||
#define INTEL_QEPCAPDIV 0x14
|
||||
#define INTEL_QEPCNTR 0x18
|
||||
#define INTEL_QEPCAPBUF 0x1c
|
||||
#define INTEL_QEPINT_STAT 0x20
|
||||
#define INTEL_QEPINT_MASK 0x24
|
||||
|
||||
/* QEPCON */
|
||||
#define INTEL_QEPCON_EN BIT(0)
|
||||
#define INTEL_QEPCON_FLT_EN BIT(1)
|
||||
#define INTEL_QEPCON_EDGE_A BIT(2)
|
||||
#define INTEL_QEPCON_EDGE_B BIT(3)
|
||||
#define INTEL_QEPCON_EDGE_INDX BIT(4)
|
||||
#define INTEL_QEPCON_SWPAB BIT(5)
|
||||
#define INTEL_QEPCON_OP_MODE BIT(6)
|
||||
#define INTEL_QEPCON_PH_ERR BIT(7)
|
||||
#define INTEL_QEPCON_COUNT_RST_MODE BIT(8)
|
||||
#define INTEL_QEPCON_INDX_GATING_MASK GENMASK(10, 9)
|
||||
#define INTEL_QEPCON_INDX_GATING(n) (((n) & 3) << 9)
|
||||
#define INTEL_QEPCON_INDX_PAL_PBL INTEL_QEPCON_INDX_GATING(0)
|
||||
#define INTEL_QEPCON_INDX_PAL_PBH INTEL_QEPCON_INDX_GATING(1)
|
||||
#define INTEL_QEPCON_INDX_PAH_PBL INTEL_QEPCON_INDX_GATING(2)
|
||||
#define INTEL_QEPCON_INDX_PAH_PBH INTEL_QEPCON_INDX_GATING(3)
|
||||
#define INTEL_QEPCON_CAP_MODE BIT(11)
|
||||
#define INTEL_QEPCON_FIFO_THRE_MASK GENMASK(14, 12)
|
||||
#define INTEL_QEPCON_FIFO_THRE(n) ((((n) - 1) & 7) << 12)
|
||||
#define INTEL_QEPCON_FIFO_EMPTY BIT(15)
|
||||
|
||||
/* QEPFLT */
|
||||
#define INTEL_QEPFLT_MAX_COUNT(n) ((n) & 0x1fffff)
|
||||
|
||||
/* QEPINT */
|
||||
#define INTEL_QEPINT_FIFOCRIT BIT(5)
|
||||
#define INTEL_QEPINT_FIFOENTRY BIT(4)
|
||||
#define INTEL_QEPINT_QEPDIR BIT(3)
|
||||
#define INTEL_QEPINT_QEPRST_UP BIT(2)
|
||||
#define INTEL_QEPINT_QEPRST_DOWN BIT(1)
|
||||
#define INTEL_QEPINT_WDT BIT(0)
|
||||
|
||||
#define INTEL_QEPINT_MASK_ALL GENMASK(5, 0)
|
||||
|
||||
#define INTEL_QEP_CLK_PERIOD_NS 10
|
||||
|
||||
#define INTEL_QEP_COUNTER_EXT_RW(_name) \
|
||||
{ \
|
||||
.name = #_name, \
|
||||
.read = _name##_read, \
|
||||
.write = _name##_write, \
|
||||
}
|
||||
|
||||
struct intel_qep {
|
||||
struct counter_device counter;
|
||||
struct mutex lock;
|
||||
struct device *dev;
|
||||
void __iomem *regs;
|
||||
bool enabled;
|
||||
/* Context save registers */
|
||||
u32 qepcon;
|
||||
u32 qepflt;
|
||||
u32 qepmax;
|
||||
};
|
||||
|
||||
static inline u32 intel_qep_readl(struct intel_qep *qep, u32 offset)
|
||||
{
|
||||
return readl(qep->regs + offset);
|
||||
}
|
||||
|
||||
static inline void intel_qep_writel(struct intel_qep *qep,
|
||||
u32 offset, u32 value)
|
||||
{
|
||||
writel(value, qep->regs + offset);
|
||||
}
|
||||
|
||||
static void intel_qep_init(struct intel_qep *qep)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
reg &= ~INTEL_QEPCON_EN;
|
||||
intel_qep_writel(qep, INTEL_QEPCON, reg);
|
||||
qep->enabled = false;
|
||||
/*
|
||||
* Make sure peripheral is disabled by flushing the write with
|
||||
* a dummy read
|
||||
*/
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
|
||||
reg &= ~(INTEL_QEPCON_OP_MODE | INTEL_QEPCON_FLT_EN);
|
||||
reg |= INTEL_QEPCON_EDGE_A | INTEL_QEPCON_EDGE_B |
|
||||
INTEL_QEPCON_EDGE_INDX | INTEL_QEPCON_COUNT_RST_MODE;
|
||||
intel_qep_writel(qep, INTEL_QEPCON, reg);
|
||||
intel_qep_writel(qep, INTEL_QEPINT_MASK, INTEL_QEPINT_MASK_ALL);
|
||||
}
|
||||
|
||||
static int intel_qep_count_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
unsigned long *val)
|
||||
{
|
||||
struct intel_qep *const qep = counter->priv;
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
*val = intel_qep_readl(qep, INTEL_QEPCOUNT);
|
||||
pm_runtime_put(qep->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const enum counter_count_function intel_qep_count_functions[] = {
|
||||
COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
|
||||
static int intel_qep_function_get(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
size_t *function)
|
||||
{
|
||||
*function = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const enum counter_synapse_action intel_qep_synapse_actions[] = {
|
||||
COUNTER_SYNAPSE_ACTION_BOTH_EDGES,
|
||||
};
|
||||
|
||||
static int intel_qep_action_get(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
struct counter_synapse *synapse,
|
||||
size_t *action)
|
||||
{
|
||||
*action = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct counter_ops intel_qep_counter_ops = {
|
||||
.count_read = intel_qep_count_read,
|
||||
.function_get = intel_qep_function_get,
|
||||
.action_get = intel_qep_action_get,
|
||||
};
|
||||
|
||||
#define INTEL_QEP_SIGNAL(_id, _name) { \
|
||||
.id = (_id), \
|
||||
.name = (_name), \
|
||||
}
|
||||
|
||||
static struct counter_signal intel_qep_signals[] = {
|
||||
INTEL_QEP_SIGNAL(0, "Phase A"),
|
||||
INTEL_QEP_SIGNAL(1, "Phase B"),
|
||||
INTEL_QEP_SIGNAL(2, "Index"),
|
||||
};
|
||||
|
||||
#define INTEL_QEP_SYNAPSE(_signal_id) { \
|
||||
.actions_list = intel_qep_synapse_actions, \
|
||||
.num_actions = ARRAY_SIZE(intel_qep_synapse_actions), \
|
||||
.signal = &intel_qep_signals[(_signal_id)], \
|
||||
}
|
||||
|
||||
static struct counter_synapse intel_qep_count_synapses[] = {
|
||||
INTEL_QEP_SYNAPSE(0),
|
||||
INTEL_QEP_SYNAPSE(1),
|
||||
INTEL_QEP_SYNAPSE(2),
|
||||
};
|
||||
|
||||
static ssize_t ceiling_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, char *buf)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 reg;
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
reg = intel_qep_readl(qep, INTEL_QEPMAX);
|
||||
pm_runtime_put(qep->dev);
|
||||
|
||||
return sysfs_emit(buf, "%u\n", reg);
|
||||
}
|
||||
|
||||
static ssize_t ceiling_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, const char *buf, size_t len)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 max;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 0, &max);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&qep->lock);
|
||||
if (qep->enabled) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
intel_qep_writel(qep, INTEL_QEPMAX, max);
|
||||
pm_runtime_put(qep->dev);
|
||||
ret = len;
|
||||
|
||||
out:
|
||||
mutex_unlock(&qep->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t enable_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, char *buf)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
|
||||
return sysfs_emit(buf, "%u\n", qep->enabled);
|
||||
}
|
||||
|
||||
static ssize_t enable_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, const char *buf, size_t len)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 reg;
|
||||
bool val, changed;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&qep->lock);
|
||||
changed = val ^ qep->enabled;
|
||||
if (!changed)
|
||||
goto out;
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
if (val) {
|
||||
/* Enable peripheral and keep runtime PM always on */
|
||||
reg |= INTEL_QEPCON_EN;
|
||||
pm_runtime_get_noresume(qep->dev);
|
||||
} else {
|
||||
/* Let runtime PM be idle and disable peripheral */
|
||||
pm_runtime_put_noidle(qep->dev);
|
||||
reg &= ~INTEL_QEPCON_EN;
|
||||
}
|
||||
intel_qep_writel(qep, INTEL_QEPCON, reg);
|
||||
pm_runtime_put(qep->dev);
|
||||
qep->enabled = val;
|
||||
|
||||
out:
|
||||
mutex_unlock(&qep->lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t spike_filter_ns_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, char *buf)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 reg;
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
if (!(reg & INTEL_QEPCON_FLT_EN)) {
|
||||
pm_runtime_put(qep->dev);
|
||||
return sysfs_emit(buf, "0\n");
|
||||
}
|
||||
reg = INTEL_QEPFLT_MAX_COUNT(intel_qep_readl(qep, INTEL_QEPFLT));
|
||||
pm_runtime_put(qep->dev);
|
||||
|
||||
return sysfs_emit(buf, "%u\n", (reg + 2) * INTEL_QEP_CLK_PERIOD_NS);
|
||||
}
|
||||
|
||||
static ssize_t spike_filter_ns_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, const char *buf, size_t len)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 reg, length;
|
||||
bool enable;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou32(buf, 0, &length);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Spike filter length is (MAX_COUNT + 2) clock periods.
|
||||
* Disable filter when userspace writes 0, enable for valid
|
||||
* nanoseconds values and error out otherwise.
|
||||
*/
|
||||
length /= INTEL_QEP_CLK_PERIOD_NS;
|
||||
if (length == 0) {
|
||||
enable = false;
|
||||
length = 0;
|
||||
} else if (length >= 2) {
|
||||
enable = true;
|
||||
length -= 2;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (length > INTEL_QEPFLT_MAX_COUNT(length))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&qep->lock);
|
||||
if (qep->enabled) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
if (enable)
|
||||
reg |= INTEL_QEPCON_FLT_EN;
|
||||
else
|
||||
reg &= ~INTEL_QEPCON_FLT_EN;
|
||||
intel_qep_writel(qep, INTEL_QEPFLT, length);
|
||||
intel_qep_writel(qep, INTEL_QEPCON, reg);
|
||||
pm_runtime_put(qep->dev);
|
||||
ret = len;
|
||||
|
||||
out:
|
||||
mutex_unlock(&qep->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t preset_enable_read(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, char *buf)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 reg;
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
pm_runtime_put(qep->dev);
|
||||
return sysfs_emit(buf, "%u\n", !(reg & INTEL_QEPCON_COUNT_RST_MODE));
|
||||
}
|
||||
|
||||
static ssize_t preset_enable_write(struct counter_device *counter,
|
||||
struct counter_count *count,
|
||||
void *priv, const char *buf, size_t len)
|
||||
{
|
||||
struct intel_qep *qep = counter->priv;
|
||||
u32 reg;
|
||||
bool val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&qep->lock);
|
||||
if (qep->enabled) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(qep->dev);
|
||||
reg = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
if (val)
|
||||
reg &= ~INTEL_QEPCON_COUNT_RST_MODE;
|
||||
else
|
||||
reg |= INTEL_QEPCON_COUNT_RST_MODE;
|
||||
|
||||
intel_qep_writel(qep, INTEL_QEPCON, reg);
|
||||
pm_runtime_put(qep->dev);
|
||||
ret = len;
|
||||
|
||||
out:
|
||||
mutex_unlock(&qep->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct counter_count_ext intel_qep_count_ext[] = {
|
||||
INTEL_QEP_COUNTER_EXT_RW(ceiling),
|
||||
INTEL_QEP_COUNTER_EXT_RW(enable),
|
||||
INTEL_QEP_COUNTER_EXT_RW(spike_filter_ns),
|
||||
INTEL_QEP_COUNTER_EXT_RW(preset_enable)
|
||||
};
|
||||
|
||||
static struct counter_count intel_qep_counter_count[] = {
|
||||
{
|
||||
.id = 0,
|
||||
.name = "Channel 1 Count",
|
||||
.functions_list = intel_qep_count_functions,
|
||||
.num_functions = ARRAY_SIZE(intel_qep_count_functions),
|
||||
.synapses = intel_qep_count_synapses,
|
||||
.num_synapses = ARRAY_SIZE(intel_qep_count_synapses),
|
||||
.ext = intel_qep_count_ext,
|
||||
.num_ext = ARRAY_SIZE(intel_qep_count_ext),
|
||||
},
|
||||
};
|
||||
|
||||
static int intel_qep_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
{
|
||||
struct intel_qep *qep;
|
||||
struct device *dev = &pci->dev;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
qep = devm_kzalloc(dev, sizeof(*qep), GFP_KERNEL);
|
||||
if (!qep)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pcim_enable_device(pci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regs = pcim_iomap_table(pci)[0];
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
qep->dev = dev;
|
||||
qep->regs = regs;
|
||||
mutex_init(&qep->lock);
|
||||
|
||||
intel_qep_init(qep);
|
||||
pci_set_drvdata(pci, qep);
|
||||
|
||||
qep->counter.name = pci_name(pci);
|
||||
qep->counter.parent = dev;
|
||||
qep->counter.ops = &intel_qep_counter_ops;
|
||||
qep->counter.counts = intel_qep_counter_count;
|
||||
qep->counter.num_counts = ARRAY_SIZE(intel_qep_counter_count);
|
||||
qep->counter.signals = intel_qep_signals;
|
||||
qep->counter.num_signals = ARRAY_SIZE(intel_qep_signals);
|
||||
qep->counter.priv = qep;
|
||||
qep->enabled = false;
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_allow(dev);
|
||||
|
||||
return devm_counter_register(&pci->dev, &qep->counter);
|
||||
}
|
||||
|
||||
static void intel_qep_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct intel_qep *qep = pci_get_drvdata(pci);
|
||||
struct device *dev = &pci->dev;
|
||||
|
||||
pm_runtime_forbid(dev);
|
||||
if (!qep->enabled)
|
||||
pm_runtime_get(dev);
|
||||
|
||||
intel_qep_writel(qep, INTEL_QEPCON, 0);
|
||||
}
|
||||
|
||||
static int __maybe_unused intel_qep_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct intel_qep *qep = pci_get_drvdata(pdev);
|
||||
|
||||
qep->qepcon = intel_qep_readl(qep, INTEL_QEPCON);
|
||||
qep->qepflt = intel_qep_readl(qep, INTEL_QEPFLT);
|
||||
qep->qepmax = intel_qep_readl(qep, INTEL_QEPMAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused intel_qep_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct intel_qep *qep = pci_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* Make sure peripheral is disabled when restoring registers and
|
||||
* control register bits that are writable only when the peripheral
|
||||
* is disabled
|
||||
*/
|
||||
intel_qep_writel(qep, INTEL_QEPCON, 0);
|
||||
intel_qep_readl(qep, INTEL_QEPCON);
|
||||
|
||||
intel_qep_writel(qep, INTEL_QEPFLT, qep->qepflt);
|
||||
intel_qep_writel(qep, INTEL_QEPMAX, qep->qepmax);
|
||||
intel_qep_writel(qep, INTEL_QEPINT_MASK, INTEL_QEPINT_MASK_ALL);
|
||||
|
||||
/* Restore all other control register bits except enable status */
|
||||
intel_qep_writel(qep, INTEL_QEPCON, qep->qepcon & ~INTEL_QEPCON_EN);
|
||||
intel_qep_readl(qep, INTEL_QEPCON);
|
||||
|
||||
/* Restore enable status */
|
||||
intel_qep_writel(qep, INTEL_QEPCON, qep->qepcon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UNIVERSAL_DEV_PM_OPS(intel_qep_pm_ops,
|
||||
intel_qep_suspend, intel_qep_resume, NULL);
|
||||
|
||||
static const struct pci_device_id intel_qep_id_table[] = {
|
||||
/* EHL */
|
||||
{ PCI_VDEVICE(INTEL, 0x4bc3), },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b81), },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b82), },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b83), },
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_qep_id_table);
|
||||
|
||||
static struct pci_driver intel_qep_driver = {
|
||||
.name = "intel-qep",
|
||||
.id_table = intel_qep_id_table,
|
||||
.probe = intel_qep_probe,
|
||||
.remove = intel_qep_remove,
|
||||
.driver = {
|
||||
.pm = &intel_qep_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
module_pci_driver(intel_qep_driver);
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi (Intel)");
|
||||
MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>");
|
||||
MODULE_AUTHOR("Raymond Tan <raymond.tan@intel.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Intel Quadrature Encoder Peripheral driver");
|
@ -77,7 +77,7 @@ static const struct counter_count_ext interrupt_cnt_ext[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static enum counter_synapse_action interrupt_cnt_synapse_actionss[] = {
|
||||
static const enum counter_synapse_action interrupt_cnt_synapse_actions[] = {
|
||||
COUNTER_SYNAPSE_ACTION_RISING_EDGE,
|
||||
};
|
||||
|
||||
@ -112,7 +112,7 @@ static int interrupt_cnt_write(struct counter_device *counter,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum counter_count_function interrupt_cnt_functions[] = {
|
||||
static const enum counter_count_function interrupt_cnt_functions[] = {
|
||||
COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
};
|
||||
|
||||
@ -194,8 +194,8 @@ static int interrupt_cnt_probe(struct platform_device *pdev)
|
||||
priv->counter.signals = &priv->signals;
|
||||
priv->counter.num_signals = 1;
|
||||
|
||||
priv->synapses.actions_list = interrupt_cnt_synapse_actionss;
|
||||
priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actionss);
|
||||
priv->synapses.actions_list = interrupt_cnt_synapse_actions;
|
||||
priv->synapses.num_actions = ARRAY_SIZE(interrupt_cnt_synapse_actions);
|
||||
priv->synapses.signal = &priv->signals;
|
||||
|
||||
priv->cnts.name = "Channel 0 Count";
|
||||
|
@ -37,7 +37,7 @@ enum mchp_tc_count_function {
|
||||
MCHP_TC_FUNCTION_QUADRATURE,
|
||||
};
|
||||
|
||||
static enum counter_count_function mchp_tc_count_functions[] = {
|
||||
static const enum counter_count_function mchp_tc_count_functions[] = {
|
||||
[MCHP_TC_FUNCTION_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[MCHP_TC_FUNCTION_QUADRATURE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
@ -49,7 +49,7 @@ enum mchp_tc_synapse_action {
|
||||
MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE
|
||||
};
|
||||
|
||||
static enum counter_synapse_action mchp_tc_synapse_actions[] = {
|
||||
static const enum counter_synapse_action mchp_tc_synapse_actions[] = {
|
||||
[MCHP_TC_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
|
||||
[MCHP_TC_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
|
||||
[MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
|
||||
|
@ -134,7 +134,7 @@ enum stm32_lptim_cnt_function {
|
||||
STM32_LPTIM_ENCODER_BOTH_EDGE,
|
||||
};
|
||||
|
||||
static enum counter_count_function stm32_lptim_cnt_functions[] = {
|
||||
static const enum counter_count_function stm32_lptim_cnt_functions[] = {
|
||||
[STM32_LPTIM_COUNTER_INCREASE] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[STM32_LPTIM_ENCODER_BOTH_EDGE] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4,
|
||||
};
|
||||
@ -146,7 +146,7 @@ enum stm32_lptim_synapse_action {
|
||||
STM32_LPTIM_SYNAPSE_ACTION_NONE,
|
||||
};
|
||||
|
||||
static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
|
||||
static const enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = {
|
||||
/* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */
|
||||
[STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE,
|
||||
[STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE] = COUNTER_SYNAPSE_ACTION_FALLING_EDGE,
|
||||
|
@ -50,7 +50,7 @@ enum stm32_count_function {
|
||||
STM32_COUNT_ENCODER_MODE_3,
|
||||
};
|
||||
|
||||
static enum counter_count_function stm32_count_functions[] = {
|
||||
static const enum counter_count_function stm32_count_functions[] = {
|
||||
[STM32_COUNT_SLAVE_MODE_DISABLED] = COUNTER_COUNT_FUNCTION_INCREASE,
|
||||
[STM32_COUNT_ENCODER_MODE_1] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A,
|
||||
[STM32_COUNT_ENCODER_MODE_2] = COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B,
|
||||
@ -267,7 +267,7 @@ enum stm32_synapse_action {
|
||||
STM32_SYNAPSE_ACTION_BOTH_EDGES
|
||||
};
|
||||
|
||||
static enum counter_synapse_action stm32_synapse_actions[] = {
|
||||
static const enum counter_synapse_action stm32_synapse_actions[] = {
|
||||
[STM32_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE,
|
||||
[STM32_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES
|
||||
};
|
||||
|
@ -89,13 +89,13 @@ config ADXL372_I2C
|
||||
module will be called adxl372_i2c.
|
||||
|
||||
config BMA180
|
||||
tristate "Bosch BMA023/BMA1x0/BMA25x 3-Axis Accelerometer Driver"
|
||||
tristate "Bosch BMA023/BMA1x0/BMA250 3-Axis Accelerometer Driver"
|
||||
depends on I2C && INPUT_BMA150=n
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say Y here if you want to build a driver for the Bosch BMA023, BMA150
|
||||
BMA180, SMB380, or BMA25x triaxial acceleration sensor.
|
||||
BMA180, BMA250 or SMB380 triaxial acceleration sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bma180.
|
||||
@ -143,9 +143,12 @@ config BMC150_ACCEL
|
||||
select BMC150_ACCEL_SPI if SPI
|
||||
help
|
||||
Say yes here to build support for the following Bosch accelerometers:
|
||||
BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
|
||||
BMA222, BMA222E, BMA250E, BMA253, BMA254, BMA255, BMA280, BMC150, BMI055.
|
||||
|
||||
Note that some of these are combo modules:
|
||||
- BMC150: accelerometer and magnetometer
|
||||
- BMI055: accelerometer and gyroscope
|
||||
|
||||
This is a combo module with both accelerometer and magnetometer.
|
||||
This driver is only implementing accelerometer part, which has
|
||||
its own address and register map.
|
||||
|
||||
@ -226,6 +229,33 @@ config DMARD10
|
||||
Choosing M will build the driver as a module. If so, the module
|
||||
will be called dmard10.
|
||||
|
||||
config FXLS8962AF
|
||||
tristate
|
||||
|
||||
config FXLS8962AF_I2C
|
||||
tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver"
|
||||
depends on I2C
|
||||
select FXLS8962AF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to build support for the NXP 3-axis automotive
|
||||
accelerometer FXLS8962AF/FXLS8964AF with I2C support.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called fxls8962af_i2c.
|
||||
|
||||
config FXLS8962AF_SPI
|
||||
tristate "NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver"
|
||||
depends on SPI
|
||||
select FXLS8962AF
|
||||
select REGMAP_SPI
|
||||
help
|
||||
Say yes here to build support for the NXP 3-axis automotive
|
||||
accelerometer FXLS8962AF/FXLS8964AF with SPI support.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called fxls8962af_spi.
|
||||
|
||||
config HID_SENSOR_ACCEL_3D
|
||||
depends on HID_SENSOR_HUB
|
||||
select IIO_BUFFER
|
||||
@ -449,6 +479,19 @@ config SCA3000
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called sca3000.
|
||||
|
||||
config SCA3300
|
||||
tristate "Murata SCA3300 3-Axis Accelerometer Driver"
|
||||
depends on SPI
|
||||
select CRC8
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Murata SCA3300 3-Axis
|
||||
accelerometer.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called sca3300.
|
||||
|
||||
config STK8312
|
||||
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
|
||||
depends on I2C
|
||||
|
@ -27,6 +27,9 @@ obj-$(CONFIG_DA311) += da311.o
|
||||
obj-$(CONFIG_DMARD06) += dmard06.o
|
||||
obj-$(CONFIG_DMARD09) += dmard09.o
|
||||
obj-$(CONFIG_DMARD10) += dmard10.o
|
||||
obj-$(CONFIG_FXLS8962AF) += fxls8962af-core.o
|
||||
obj-$(CONFIG_FXLS8962AF_I2C) += fxls8962af-i2c.o
|
||||
obj-$(CONFIG_FXLS8962AF_SPI) += fxls8962af-spi.o
|
||||
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
|
||||
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
|
||||
obj-$(CONFIG_KXSD9) += kxsd9.o
|
||||
@ -50,6 +53,7 @@ obj-$(CONFIG_MXC4005) += mxc4005.o
|
||||
obj-$(CONFIG_MXC6255) += mxc6255.o
|
||||
|
||||
obj-$(CONFIG_SCA3000) += sca3000.o
|
||||
obj-$(CONFIG_SCA3300) += sca3300.o
|
||||
|
||||
obj-$(CONFIG_STK8312) += stk8312.o
|
||||
obj-$(CONFIG_STK8BA50) += stk8ba50.o
|
||||
|
@ -8,10 +8,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
@ -7,11 +7,8 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
@ -1223,14 +1223,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
|
||||
st->dready_trig = devm_iio_trigger_alloc(dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (st->dready_trig == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
|
||||
"%s-dev%d-peak",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!st->peak_datardy_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
* BMA023/BMA150/SMB380: 7-bit I2C slave address 0x38
|
||||
* BMA180: 7-bit I2C slave address 0x40 or 0x41
|
||||
* BMA250: 7-bit I2C slave address 0x18 or 0x19
|
||||
* BMA254: 7-bit I2C slave address 0x18 or 0x19
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -38,7 +37,6 @@ enum chip_ids {
|
||||
BMA150,
|
||||
BMA180,
|
||||
BMA250,
|
||||
BMA254,
|
||||
};
|
||||
|
||||
struct bma180_data;
|
||||
@ -55,11 +53,10 @@ struct bma180_part_info {
|
||||
|
||||
u8 int_reset_reg, int_reset_mask;
|
||||
u8 sleep_reg, sleep_mask;
|
||||
u8 bw_reg, bw_mask;
|
||||
u8 bw_reg, bw_mask, bw_offset;
|
||||
u8 scale_reg, scale_mask;
|
||||
u8 power_reg, power_mask, lowpower_val;
|
||||
u8 int_enable_reg, int_enable_mask;
|
||||
u8 int_map_reg, int_enable_dataready_int1_mask;
|
||||
u8 softreset_reg, softreset_val;
|
||||
|
||||
int (*chip_config)(struct bma180_data *data);
|
||||
@ -112,7 +109,6 @@ struct bma180_part_info {
|
||||
#define BMA023_ID_REG_VAL 0x02
|
||||
#define BMA180_ID_REG_VAL 0x03
|
||||
#define BMA250_ID_REG_VAL 0x03
|
||||
#define BMA254_ID_REG_VAL 0xfa /* 250 decimal */
|
||||
|
||||
/* Chip power modes */
|
||||
#define BMA180_LOW_POWER 0x03
|
||||
@ -127,29 +123,13 @@ struct bma180_part_info {
|
||||
|
||||
#define BMA250_RANGE_MASK GENMASK(3, 0) /* Range of accel values */
|
||||
#define BMA250_BW_MASK GENMASK(4, 0) /* Accel bandwidth */
|
||||
#define BMA250_BW_OFFSET 8
|
||||
#define BMA250_SUSPEND_MASK BIT(7) /* chip will sleep */
|
||||
#define BMA250_LOWPOWER_MASK BIT(6)
|
||||
#define BMA250_DATA_INTEN_MASK BIT(4)
|
||||
#define BMA250_INT1_DATA_MASK BIT(0)
|
||||
#define BMA250_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
|
||||
|
||||
#define BMA254_RANGE_REG 0x0f
|
||||
#define BMA254_BW_REG 0x10
|
||||
#define BMA254_POWER_REG 0x11
|
||||
#define BMA254_RESET_REG 0x14
|
||||
#define BMA254_INT_ENABLE_REG 0x17
|
||||
#define BMA254_INT_MAP_REG 0x1a
|
||||
#define BMA254_INT_RESET_REG 0x21
|
||||
|
||||
#define BMA254_RANGE_MASK GENMASK(3, 0) /* Range of accel values */
|
||||
#define BMA254_BW_MASK GENMASK(4, 0) /* Accel bandwidth */
|
||||
#define BMA254_SUSPEND_MASK BIT(7) /* chip will sleep */
|
||||
#define BMA254_LOWPOWER_MASK BIT(6)
|
||||
#define BMA254_DATA_INTEN_MASK BIT(4)
|
||||
#define BMA254_INT2_DATA_MASK BIT(7)
|
||||
#define BMA254_INT1_DATA_MASK BIT(0)
|
||||
#define BMA254_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
|
||||
|
||||
struct bma180_data {
|
||||
struct regulator *vdd_supply;
|
||||
struct regulator *vddio_supply;
|
||||
@ -162,7 +142,11 @@ struct bma180_data {
|
||||
int scale;
|
||||
int bw;
|
||||
bool pmode;
|
||||
u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */
|
||||
/* Ensure timestamp is naturally aligned */
|
||||
struct {
|
||||
s16 chan[4];
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
};
|
||||
|
||||
enum bma180_chan {
|
||||
@ -178,8 +162,8 @@ static int bma023_scale_table[] = { 2452, 4903, 9709, };
|
||||
static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
|
||||
static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };
|
||||
|
||||
static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
|
||||
static int bma25x_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
|
||||
static int bma250_bw_table[] = { 8, 16, 31, 63, 125, 250, 500, 1000 }; /* Hz */
|
||||
static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
|
||||
0, 0, 306458 };
|
||||
|
||||
static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan)
|
||||
@ -283,7 +267,8 @@ static int bma180_set_bw(struct bma180_data *data, int val)
|
||||
for (i = 0; i < data->part_info->num_bw; ++i) {
|
||||
if (data->part_info->bw_table[i] == val) {
|
||||
ret = bma180_set_bits(data, data->part_info->bw_reg,
|
||||
data->part_info->bw_mask, i);
|
||||
data->part_info->bw_mask,
|
||||
i + data->part_info->bw_offset);
|
||||
if (ret) {
|
||||
dev_err(&data->client->dev,
|
||||
"failed to set bandwidth\n");
|
||||
@ -425,7 +410,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bma25x_chip_config(struct bma180_data *data)
|
||||
static int bma250_chip_config(struct bma180_data *data)
|
||||
{
|
||||
int ret = bma180_chip_init(data);
|
||||
|
||||
@ -444,8 +429,7 @@ static int bma25x_chip_config(struct bma180_data *data)
|
||||
* This enables dataready interrupt on the INT1 pin
|
||||
* FIXME: support using the INT2 pin
|
||||
*/
|
||||
ret = bma180_set_bits(data, data->part_info->int_map_reg,
|
||||
data->part_info->int_enable_dataready_int1_mask, 1);
|
||||
ret = bma180_set_bits(data, BMA250_INT_MAP_REG, BMA250_INT1_DATA_MASK, 1);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -482,7 +466,7 @@ err:
|
||||
dev_err(&data->client->dev, "failed to disable the chip\n");
|
||||
}
|
||||
|
||||
static void bma25x_chip_disable(struct bma180_data *data)
|
||||
static void bma250_chip_disable(struct bma180_data *data)
|
||||
{
|
||||
if (bma180_set_new_data_intr_state(data, false))
|
||||
goto err;
|
||||
@ -768,14 +752,6 @@ static const struct iio_chan_spec bma250_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec bma254_channels[] = {
|
||||
BMA180_ACC_CHANNEL(X, 12),
|
||||
BMA180_ACC_CHANNEL(Y, 12),
|
||||
BMA180_ACC_CHANNEL(Z, 12),
|
||||
BMA180_TEMP_CHANNEL,
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static const struct bma180_part_info bma180_part_info[] = {
|
||||
[BMA023] = {
|
||||
.chip_id = BMA023_ID_REG_VAL,
|
||||
@ -865,10 +841,10 @@ static const struct bma180_part_info bma180_part_info[] = {
|
||||
.chip_id = BMA250_ID_REG_VAL,
|
||||
.channels = bma250_channels,
|
||||
.num_channels = ARRAY_SIZE(bma250_channels),
|
||||
.scale_table = bma25x_scale_table,
|
||||
.num_scales = ARRAY_SIZE(bma25x_scale_table),
|
||||
.bw_table = bma25x_bw_table,
|
||||
.num_bw = ARRAY_SIZE(bma25x_bw_table),
|
||||
.scale_table = bma250_scale_table,
|
||||
.num_scales = ARRAY_SIZE(bma250_scale_table),
|
||||
.bw_table = bma250_bw_table,
|
||||
.num_bw = ARRAY_SIZE(bma250_bw_table),
|
||||
.temp_offset = 48, /* 0 LSB @ 24 degree C */
|
||||
.int_reset_reg = BMA250_INT_RESET_REG,
|
||||
.int_reset_mask = BMA250_INT_RESET_MASK,
|
||||
@ -876,6 +852,7 @@ static const struct bma180_part_info bma180_part_info[] = {
|
||||
.sleep_mask = BMA250_SUSPEND_MASK,
|
||||
.bw_reg = BMA250_BW_REG,
|
||||
.bw_mask = BMA250_BW_MASK,
|
||||
.bw_offset = BMA250_BW_OFFSET,
|
||||
.scale_reg = BMA250_RANGE_REG,
|
||||
.scale_mask = BMA250_RANGE_MASK,
|
||||
.power_reg = BMA250_POWER_REG,
|
||||
@ -883,41 +860,10 @@ static const struct bma180_part_info bma180_part_info[] = {
|
||||
.lowpower_val = 1,
|
||||
.int_enable_reg = BMA250_INT_ENABLE_REG,
|
||||
.int_enable_mask = BMA250_DATA_INTEN_MASK,
|
||||
.int_map_reg = BMA250_INT_MAP_REG,
|
||||
.int_enable_dataready_int1_mask = BMA250_INT1_DATA_MASK,
|
||||
.softreset_reg = BMA250_RESET_REG,
|
||||
.softreset_val = BMA180_RESET_VAL,
|
||||
.chip_config = bma25x_chip_config,
|
||||
.chip_disable = bma25x_chip_disable,
|
||||
},
|
||||
[BMA254] = {
|
||||
.chip_id = BMA254_ID_REG_VAL,
|
||||
.channels = bma254_channels,
|
||||
.num_channels = ARRAY_SIZE(bma254_channels),
|
||||
.scale_table = bma25x_scale_table,
|
||||
.num_scales = ARRAY_SIZE(bma25x_scale_table),
|
||||
.bw_table = bma25x_bw_table,
|
||||
.num_bw = ARRAY_SIZE(bma25x_bw_table),
|
||||
.temp_offset = 46, /* 0 LSB @ 23 degree C */
|
||||
.int_reset_reg = BMA254_INT_RESET_REG,
|
||||
.int_reset_mask = BMA254_INT_RESET_MASK,
|
||||
.sleep_reg = BMA254_POWER_REG,
|
||||
.sleep_mask = BMA254_SUSPEND_MASK,
|
||||
.bw_reg = BMA254_BW_REG,
|
||||
.bw_mask = BMA254_BW_MASK,
|
||||
.scale_reg = BMA254_RANGE_REG,
|
||||
.scale_mask = BMA254_RANGE_MASK,
|
||||
.power_reg = BMA254_POWER_REG,
|
||||
.power_mask = BMA254_LOWPOWER_MASK,
|
||||
.lowpower_val = 1,
|
||||
.int_enable_reg = BMA254_INT_ENABLE_REG,
|
||||
.int_enable_mask = BMA254_DATA_INTEN_MASK,
|
||||
.int_map_reg = BMA254_INT_MAP_REG,
|
||||
.int_enable_dataready_int1_mask = BMA254_INT1_DATA_MASK,
|
||||
.softreset_reg = BMA254_RESET_REG,
|
||||
.softreset_val = BMA180_RESET_VAL,
|
||||
.chip_config = bma25x_chip_config,
|
||||
.chip_disable = bma25x_chip_disable,
|
||||
.chip_config = bma250_chip_config,
|
||||
.chip_disable = bma250_chip_disable,
|
||||
},
|
||||
};
|
||||
|
||||
@ -938,12 +884,12 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p)
|
||||
mutex_unlock(&data->mutex);
|
||||
goto err;
|
||||
}
|
||||
((s16 *)data->buff)[i++] = ret;
|
||||
data->scan.chan[i++] = ret;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns);
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
@ -997,8 +943,7 @@ static int bma180_probe(struct i2c_client *client,
|
||||
chip = id->driver_data;
|
||||
data->part_info = &bma180_part_info[chip];
|
||||
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1045,7 +990,7 @@ static int bma180_probe(struct i2c_client *client,
|
||||
|
||||
if (client->irq > 0) {
|
||||
data->trig = iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!data->trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_chip_disable;
|
||||
@ -1158,7 +1103,6 @@ static const struct i2c_device_id bma180_ids[] = {
|
||||
{ "bma150", BMA150 },
|
||||
{ "bma180", BMA180 },
|
||||
{ "bma250", BMA250 },
|
||||
{ "bma254", BMA254 },
|
||||
{ "smb380", BMA150 },
|
||||
{ }
|
||||
};
|
||||
@ -1182,10 +1126,6 @@ static const struct of_device_id bma180_of_match[] = {
|
||||
.compatible = "bosch,bma250",
|
||||
.data = (void *)BMA250
|
||||
},
|
||||
{
|
||||
.compatible = "bosch,bma254",
|
||||
.data = (void *)BMA254
|
||||
},
|
||||
{
|
||||
.compatible = "bosch,smb380",
|
||||
.data = (void *)BMA150
|
||||
@ -1209,5 +1149,5 @@ module_i2c_driver(bma180_driver);
|
||||
|
||||
MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
|
||||
MODULE_AUTHOR("Texas Instruments, Inc.");
|
||||
MODULE_DESCRIPTION("Bosch BMA023/BMA1x0/BMA25x triaxial acceleration sensor");
|
||||
MODULE_DESCRIPTION("Bosch BMA023/BMA1x0/BMA250 triaxial acceleration sensor");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -63,7 +63,11 @@ static const int bma220_scale_table[][2] = {
|
||||
struct bma220_data {
|
||||
struct spi_device *spi_device;
|
||||
struct mutex lock;
|
||||
s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 8x8 timestamp */
|
||||
struct {
|
||||
s8 chans[3];
|
||||
/* Ensure timestamp is naturally aligned. */
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
u8 tx_buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
@ -94,12 +98,12 @@ static irqreturn_t bma220_trigger_handler(int irq, void *p)
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK;
|
||||
ret = spi_write_then_read(spi, data->tx_buf, 1, data->buffer,
|
||||
ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans,
|
||||
ARRAY_SIZE(bma220_channels) - 1);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
pf->timestamp);
|
||||
err:
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -811,7 +811,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation);
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1,14 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
|
||||
* - BMC150
|
||||
* - BMI055
|
||||
* - BMA255
|
||||
* - BMA250E
|
||||
* - BMA222
|
||||
* - BMA222E
|
||||
* - BMA280
|
||||
*
|
||||
* 3-axis accelerometer driver supporting many Bosch-Sensortec chips
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*/
|
||||
|
||||
@ -157,59 +149,6 @@ struct bmc150_accel_chip_info {
|
||||
const struct bmc150_scale_info scale_table[4];
|
||||
};
|
||||
|
||||
struct bmc150_accel_interrupt {
|
||||
const struct bmc150_accel_interrupt_info *info;
|
||||
atomic_t users;
|
||||
};
|
||||
|
||||
struct bmc150_accel_trigger {
|
||||
struct bmc150_accel_data *data;
|
||||
struct iio_trigger *indio_trig;
|
||||
int (*setup)(struct bmc150_accel_trigger *t, bool state);
|
||||
int intr;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
enum bmc150_accel_interrupt_id {
|
||||
BMC150_ACCEL_INT_DATA_READY,
|
||||
BMC150_ACCEL_INT_ANY_MOTION,
|
||||
BMC150_ACCEL_INT_WATERMARK,
|
||||
BMC150_ACCEL_INTERRUPTS,
|
||||
};
|
||||
|
||||
enum bmc150_accel_trigger_id {
|
||||
BMC150_ACCEL_TRIGGER_DATA_READY,
|
||||
BMC150_ACCEL_TRIGGER_ANY_MOTION,
|
||||
BMC150_ACCEL_TRIGGERS,
|
||||
};
|
||||
|
||||
struct bmc150_accel_data {
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
|
||||
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
|
||||
struct mutex mutex;
|
||||
u8 fifo_mode, watermark;
|
||||
s16 buffer[8];
|
||||
/*
|
||||
* Ensure there is sufficient space and correct alignment for
|
||||
* the timestamp if enabled
|
||||
*/
|
||||
struct {
|
||||
__le16 channels[3];
|
||||
s64 ts __aligned(8);
|
||||
} scan;
|
||||
u8 bw_bits;
|
||||
u32 slope_dur;
|
||||
u32 slope_thres;
|
||||
u32 range;
|
||||
int ev_enable_state;
|
||||
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
|
||||
const struct bmc150_accel_chip_info *chip_info;
|
||||
struct i2c_client *second_device;
|
||||
struct iio_mount_matrix orientation;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
int val;
|
||||
int val2;
|
||||
@ -389,7 +328,7 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
|
||||
int ret;
|
||||
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
ret = pm_runtime_put_autosuspend(dev);
|
||||
@ -398,9 +337,6 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"Failed: %s for %d\n", __func__, on);
|
||||
if (on)
|
||||
pm_runtime_put_noidle(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -439,8 +375,8 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
|
||||
* Onda V80 plus
|
||||
* Predia Basic Tablet
|
||||
*/
|
||||
static bool bmc150_apply_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
static bool bmc150_apply_bosc0200_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
@ -450,9 +386,6 @@ static bool bmc150_apply_acpi_orientation(struct device *dev,
|
||||
acpi_status status;
|
||||
int i, j, val[3];
|
||||
|
||||
if (!adev || !acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
|
||||
return false;
|
||||
|
||||
if (strcmp(dev_name(dev), "i2c-BOSC0200:base") == 0) {
|
||||
alt_name = "ROMK";
|
||||
label = "accel-base";
|
||||
@ -508,6 +441,33 @@ unknown_format:
|
||||
kfree(buffer.pointer);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bmc150_apply_dual250e_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
|
||||
if (strcmp(dev_name(dev), "i2c-DUAL250E:base") == 0)
|
||||
indio_dev->label = "accel-base";
|
||||
else
|
||||
indio_dev->label = "accel-display";
|
||||
|
||||
return false; /* DUAL250E fwnodes have no mount matrix info */
|
||||
}
|
||||
|
||||
static bool bmc150_apply_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
if (adev && acpi_dev_hid_uid_match(adev, "BOSC0200", NULL))
|
||||
return bmc150_apply_bosc0200_acpi_orientation(dev, orientation);
|
||||
|
||||
if (adev && acpi_dev_hid_uid_match(adev, "DUAL250E", NULL))
|
||||
return bmc150_apply_dual250e_acpi_orientation(dev, orientation);
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static bool bmc150_apply_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
@ -1128,80 +1088,63 @@ static const struct iio_chan_spec bmc150_accel_channels[] =
|
||||
static const struct iio_chan_spec bma280_accel_channels[] =
|
||||
BMC150_ACCEL_CHANNELS(14);
|
||||
|
||||
/*
|
||||
* The range for the Bosch sensors is typically +-2g/4g/8g/16g, distributed
|
||||
* over the amount of bits (see above). The scale table can be calculated using
|
||||
* (range / 2^bits) * g = (range / 2^bits) * 9.80665 m/s^2
|
||||
* e.g. for +-2g and 12 bits: (4 / 2^12) * 9.80665 m/s^2 = 0.0095768... m/s^2
|
||||
* Multiply 10^6 and round to get the values listed below.
|
||||
*/
|
||||
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
|
||||
[bmc150] = {
|
||||
.name = "BMC150A",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
.scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{19122, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{38344, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bmi055] = {
|
||||
.name = "BMI055A",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
.scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{19122, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{38344, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma255] = {
|
||||
.name = "BMA0255",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
.scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{19122, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{38344, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma250e] = {
|
||||
.name = "BMA250E",
|
||||
.chip_id = 0xF9,
|
||||
.channels = bma250e_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma250e_accel_channels),
|
||||
.scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{76590, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{153277, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{306457, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma222] = {
|
||||
{
|
||||
.name = "BMA222",
|
||||
.chip_id = 0x03,
|
||||
.channels = bma222e_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
|
||||
/*
|
||||
* The datasheet page 17 says:
|
||||
* 15.6, 31.3, 62.5 and 125 mg per LSB.
|
||||
*/
|
||||
.scale_table = { {156000, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{313000, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{625000, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{1250000, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
.scale_table = { {153229, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{306458, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{612916, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{1225831, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma222e] = {
|
||||
{
|
||||
.name = "BMA222E",
|
||||
.chip_id = 0xF8,
|
||||
.channels = bma222e_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
|
||||
.scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{306457, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{612915, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
.scale_table = { {153229, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{306458, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{612916, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{1225831, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
[bma280] = {
|
||||
.name = "BMA0280",
|
||||
{
|
||||
.name = "BMA250E",
|
||||
.chip_id = 0xF9,
|
||||
.channels = bma250e_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma250e_accel_channels),
|
||||
.scale_table = { {38307, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{76614, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{153229, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{306458, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
{
|
||||
.name = "BMA253/BMA254/BMA255/BMC150/BMI055",
|
||||
.chip_id = 0xFA,
|
||||
.channels = bmc150_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
|
||||
.scale_table = { {9577, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{19154, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{38307, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{76614, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
{
|
||||
.name = "BMA280",
|
||||
.chip_id = 0xFB,
|
||||
.channels = bma280_accel_channels,
|
||||
.num_channels = ARRAY_SIZE(bma280_accel_channels),
|
||||
.scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{4785, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{9581, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{19152, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
.scale_table = { {2394, BMC150_ACCEL_DEF_RANGE_2G},
|
||||
{4788, BMC150_ACCEL_DEF_RANGE_4G},
|
||||
{9577, BMC150_ACCEL_DEF_RANGE_8G},
|
||||
{19154, BMC150_ACCEL_DEF_RANGE_16G} },
|
||||
},
|
||||
};
|
||||
|
||||
@ -1470,9 +1413,9 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
|
||||
struct bmc150_accel_trigger *t = &data->triggers[i];
|
||||
|
||||
t->indio_trig = devm_iio_trigger_alloc(dev,
|
||||
bmc150_accel_triggers[i].name,
|
||||
bmc150_accel_triggers[i].name,
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!t->indio_trig) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
@ -1688,8 +1631,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
data->regmap = regmap;
|
||||
|
||||
if (!bmc150_apply_acpi_orientation(dev, &data->orientation)) {
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -1807,26 +1749,6 @@ err_disable_regulators:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
|
||||
|
||||
struct i2c_client *bmc150_get_second_device(struct i2c_client *client)
|
||||
{
|
||||
struct bmc150_accel_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
return data->second_device;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bmc150_get_second_device);
|
||||
|
||||
void bmc150_set_second_device(struct i2c_client *client)
|
||||
{
|
||||
struct bmc150_accel_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (data)
|
||||
data->second_device = client;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bmc150_set_second_device);
|
||||
|
||||
int bmc150_accel_core_remove(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
@ -1836,7 +1758,6 @@ int bmc150_accel_core_remove(struct device *dev)
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
|
||||
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
|
||||
|
||||
@ -1876,6 +1797,9 @@ static int bmc150_accel_resume(struct device *dev)
|
||||
bmc150_accel_fifo_set_mode(data);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
if (data->resume_callback)
|
||||
data->resume_callback(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -1,14 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips:
|
||||
* - BMC150
|
||||
* - BMI055
|
||||
* - BMA255
|
||||
* - BMA250E
|
||||
* - BMA222
|
||||
* - BMA222E
|
||||
* - BMA280
|
||||
*
|
||||
* 3-axis accelerometer driver supporting many I2C Bosch-Sensortec chips
|
||||
* Copyright (c) 2014, Intel Corporation.
|
||||
*/
|
||||
|
||||
@ -21,6 +13,164 @@
|
||||
|
||||
#include "bmc150-accel.h"
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id bmc150_acpi_dual_accel_ids[] = {
|
||||
{"BOSC0200"},
|
||||
{"DUAL250E"},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* The DUAL250E ACPI device for 360° hinges type 2-in-1s with 1 accelerometer
|
||||
* in the display and 1 in the hinge has an ACPI-method (DSM) to tell the
|
||||
* ACPI code about the angle between the 2 halves. This will make the ACPI
|
||||
* code enable/disable the keyboard and touchpad. We need to call this to avoid
|
||||
* the keyboard being disabled when the 2-in-1 is turned-on or resumed while
|
||||
* fully folded into tablet mode (which gets detected with a HALL-sensor).
|
||||
* If we don't call this then the keyboard won't work even when the 2-in-1 is
|
||||
* changed to be used in laptop mode after the power-on / resume.
|
||||
*
|
||||
* This DSM takes 2 angles, selected by setting aux0 to 0 or 1, these presumably
|
||||
* define the angle between the gravity vector measured by the accelerometer in
|
||||
* the display (aux0=0) resp. the base (aux0=1) and some reference vector.
|
||||
* The 2 angles get subtracted from each other so the reference vector does
|
||||
* not matter and we can simply leave the second angle at 0.
|
||||
*/
|
||||
|
||||
#define BMC150_DSM_GUID "7681541e-8827-4239-8d9d-36be7fe12542"
|
||||
#define DUAL250E_SET_ANGLE_FN_INDEX 3
|
||||
|
||||
struct dual250e_set_angle_args {
|
||||
u32 aux0;
|
||||
u32 ang0;
|
||||
u32 rawx;
|
||||
u32 rawy;
|
||||
u32 rawz;
|
||||
} __packed;
|
||||
|
||||
static bool bmc150_acpi_set_angle_dsm(struct i2c_client *client, u32 aux0, u32 ang0)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
|
||||
struct dual250e_set_angle_args args = {
|
||||
.aux0 = aux0,
|
||||
.ang0 = ang0,
|
||||
};
|
||||
union acpi_object args_obj, *obj;
|
||||
guid_t guid;
|
||||
|
||||
if (!acpi_dev_hid_uid_match(adev, "DUAL250E", NULL))
|
||||
return false;
|
||||
|
||||
guid_parse(BMC150_DSM_GUID, &guid);
|
||||
|
||||
if (!acpi_check_dsm(adev->handle, &guid, 0, BIT(DUAL250E_SET_ANGLE_FN_INDEX)))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Note this triggers the following warning:
|
||||
* "ACPI Warning: \_SB.PCI0.I2C2.ACC1._DSM: Argument #4 type mismatch -
|
||||
* Found [Buffer], ACPI requires [Package]"
|
||||
* This is unavoidable since the _DSM implementation expects a "naked"
|
||||
* buffer, so wrapping it in a package will _not_ work.
|
||||
*/
|
||||
args_obj.type = ACPI_TYPE_BUFFER;
|
||||
args_obj.buffer.length = sizeof(args);
|
||||
args_obj.buffer.pointer = (u8 *)&args;
|
||||
|
||||
obj = acpi_evaluate_dsm(adev->handle, &guid, 0, DUAL250E_SET_ANGLE_FN_INDEX, &args_obj);
|
||||
if (!obj) {
|
||||
dev_err(&client->dev, "Failed to call DSM to enable keyboard and touchpad\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ACPI_FREE(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool bmc150_acpi_enable_keyboard(struct i2c_client *client)
|
||||
{
|
||||
/*
|
||||
* The EC must see a change for it to re-enable the kbd, so first
|
||||
* set the angle to 270° (tent/stand mode) and then change it to
|
||||
* 90° (laptop mode).
|
||||
*/
|
||||
if (!bmc150_acpi_set_angle_dsm(client, 0, 270))
|
||||
return false;
|
||||
|
||||
/* The EC needs some time to notice the angle being changed */
|
||||
msleep(100);
|
||||
|
||||
return bmc150_acpi_set_angle_dsm(client, 0, 90);
|
||||
}
|
||||
|
||||
static void bmc150_acpi_resume_work(struct work_struct *work)
|
||||
{
|
||||
struct bmc150_accel_data *data =
|
||||
container_of(work, struct bmc150_accel_data, resume_work.work);
|
||||
|
||||
bmc150_acpi_enable_keyboard(data->second_device);
|
||||
}
|
||||
|
||||
static void bmc150_acpi_resume_handler(struct device *dev)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
|
||||
/*
|
||||
* Delay the bmc150_acpi_enable_keyboard() call till after the system
|
||||
* resume has completed, otherwise it will not work.
|
||||
*/
|
||||
schedule_delayed_work(&data->resume_work, msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
/*
|
||||
* Some acpi_devices describe 2 accelerometers in a single ACPI device,
|
||||
* try instantiating a second i2c_client for an I2cSerialBusV2 ACPI resource
|
||||
* with index 1.
|
||||
*/
|
||||
static void bmc150_acpi_dual_accel_probe(struct i2c_client *client)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(i2c_get_clientdata(client));
|
||||
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
|
||||
char dev_name[16];
|
||||
struct i2c_board_info board_info = {
|
||||
.type = "bmc150_accel",
|
||||
.dev_name = dev_name,
|
||||
.fwnode = client->dev.fwnode,
|
||||
};
|
||||
|
||||
if (acpi_match_device_ids(adev, bmc150_acpi_dual_accel_ids))
|
||||
return;
|
||||
|
||||
/*
|
||||
* The 2nd accel sits in the base of 2-in-1s. The suffix is static, as
|
||||
* there should never be more then 1 ACPI node with 2 accelerometers.
|
||||
*/
|
||||
snprintf(dev_name, sizeof(dev_name), "%s:base", acpi_device_hid(adev));
|
||||
|
||||
board_info.irq = acpi_dev_gpio_irq_get(adev, 1);
|
||||
|
||||
data->second_device = i2c_acpi_new_device(&client->dev, 1, &board_info);
|
||||
|
||||
if (!IS_ERR(data->second_device) && bmc150_acpi_enable_keyboard(data->second_device)) {
|
||||
INIT_DELAYED_WORK(&data->resume_work, bmc150_acpi_resume_work);
|
||||
data->resume_callback = bmc150_acpi_resume_handler;
|
||||
}
|
||||
}
|
||||
|
||||
static void bmc150_acpi_dual_accel_remove(struct i2c_client *client)
|
||||
{
|
||||
struct bmc150_accel_data *data = iio_priv(i2c_get_clientdata(client));
|
||||
|
||||
if (data->resume_callback)
|
||||
cancel_delayed_work_sync(&data->resume_work);
|
||||
|
||||
i2c_unregister_device(data->second_device);
|
||||
}
|
||||
#else
|
||||
static void bmc150_acpi_dual_accel_probe(struct i2c_client *client) {}
|
||||
static void bmc150_acpi_dual_accel_remove(struct i2c_client *client) {}
|
||||
#endif
|
||||
|
||||
static int bmc150_accel_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -30,7 +180,6 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
||||
i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
|
||||
i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
|
||||
struct acpi_device __maybe_unused *adev;
|
||||
int ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
|
||||
@ -47,80 +196,62 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Some BOSC0200 acpi_devices describe 2 accelerometers in a single ACPI
|
||||
* device, try instantiating a second i2c_client for an I2cSerialBusV2
|
||||
* ACPI resource with index 1. The !id check avoids recursion when
|
||||
* bmc150_accel_probe() gets called for the second client.
|
||||
* The !id check avoids recursion when probe() gets called
|
||||
* for the second client.
|
||||
*/
|
||||
#ifdef CONFIG_ACPI
|
||||
adev = ACPI_COMPANION(&client->dev);
|
||||
if (!id && adev && strcmp(acpi_device_hid(adev), "BOSC0200") == 0) {
|
||||
struct i2c_board_info board_info = {
|
||||
.type = "bmc150_accel",
|
||||
/*
|
||||
* The 2nd accel sits in the base of 2-in-1s. Note this
|
||||
* name is static, as there should never be more then 1
|
||||
* BOSC0200 ACPI node with 2 accelerometers in it.
|
||||
*/
|
||||
.dev_name = "BOSC0200:base",
|
||||
.fwnode = client->dev.fwnode,
|
||||
.irq = -ENOENT,
|
||||
};
|
||||
struct i2c_client *second_dev;
|
||||
|
||||
second_dev = i2c_acpi_new_device(&client->dev, 1, &board_info);
|
||||
if (!IS_ERR(second_dev))
|
||||
bmc150_set_second_device(second_dev);
|
||||
}
|
||||
#endif
|
||||
if (!id && has_acpi_companion(&client->dev))
|
||||
bmc150_acpi_dual_accel_probe(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmc150_accel_remove(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_client *second_dev = bmc150_get_second_device(client);
|
||||
|
||||
i2c_unregister_device(second_dev);
|
||||
bmc150_acpi_dual_accel_remove(client);
|
||||
|
||||
return bmc150_accel_core_remove(&client->dev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
|
||||
{"BSBA0150", bmc150},
|
||||
{"BMC150A", bmc150},
|
||||
{"BMI055A", bmi055},
|
||||
{"BMA0255", bma255},
|
||||
{"BMA250E", bma250e},
|
||||
{"BMA222", bma222},
|
||||
{"BMA222E", bma222e},
|
||||
{"BMA0280", bma280},
|
||||
{"BMA0255"},
|
||||
{"BMA0280"},
|
||||
{"BMA222"},
|
||||
{"BMA222E"},
|
||||
{"BMA250E"},
|
||||
{"BMC150A"},
|
||||
{"BMI055A"},
|
||||
{"BOSC0200"},
|
||||
{"BSBA0150"},
|
||||
{"DUAL250E"},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
|
||||
|
||||
static const struct i2c_device_id bmc150_accel_id[] = {
|
||||
{"bmc150_accel", bmc150},
|
||||
{"bmi055_accel", bmi055},
|
||||
{"bma255", bma255},
|
||||
{"bma250e", bma250e},
|
||||
{"bma222", bma222},
|
||||
{"bma222e", bma222e},
|
||||
{"bma280", bma280},
|
||||
{"bma222"},
|
||||
{"bma222e"},
|
||||
{"bma250e"},
|
||||
{"bma253"},
|
||||
{"bma254"},
|
||||
{"bma255"},
|
||||
{"bma280"},
|
||||
{"bmc150_accel"},
|
||||
{"bmi055_accel"},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
|
||||
|
||||
static const struct of_device_id bmc150_accel_of_match[] = {
|
||||
{ .compatible = "bosch,bmc150_accel" },
|
||||
{ .compatible = "bosch,bmi055_accel" },
|
||||
{ .compatible = "bosch,bma255" },
|
||||
{ .compatible = "bosch,bma250e" },
|
||||
{ .compatible = "bosch,bma222" },
|
||||
{ .compatible = "bosch,bma222e" },
|
||||
{ .compatible = "bosch,bma250e" },
|
||||
{ .compatible = "bosch,bma253" },
|
||||
{ .compatible = "bosch,bma254" },
|
||||
{ .compatible = "bosch,bma255" },
|
||||
{ .compatible = "bosch,bma280" },
|
||||
{ .compatible = "bosch,bmc150_accel" },
|
||||
{ .compatible = "bosch,bmi055_accel" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bmc150_accel_of_match);
|
||||
|
@ -34,26 +34,27 @@ static int bmc150_accel_remove(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
|
||||
{"BSBA0150", bmc150},
|
||||
{"BMC150A", bmc150},
|
||||
{"BMI055A", bmi055},
|
||||
{"BMA0255", bma255},
|
||||
{"BMA250E", bma250e},
|
||||
{"BMA222", bma222},
|
||||
{"BMA222E", bma222e},
|
||||
{"BMA0280", bma280},
|
||||
{"BMA0255"},
|
||||
{"BMA0280"},
|
||||
{"BMA222"},
|
||||
{"BMA222E"},
|
||||
{"BMA250E"},
|
||||
{"BMC150A"},
|
||||
{"BMI055A"},
|
||||
{"BSBA0150"},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
|
||||
|
||||
static const struct spi_device_id bmc150_accel_id[] = {
|
||||
{"bmc150_accel", bmc150},
|
||||
{"bmi055_accel", bmi055},
|
||||
{"bma255", bma255},
|
||||
{"bma250e", bma250e},
|
||||
{"bma222", bma222},
|
||||
{"bma222e", bma222e},
|
||||
{"bma280", bma280},
|
||||
{"bma222"},
|
||||
{"bma222e"},
|
||||
{"bma250e"},
|
||||
{"bma253"},
|
||||
{"bma255"},
|
||||
{"bma280"},
|
||||
{"bmc150_accel"},
|
||||
{"bmi055_accel"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
|
||||
|
@ -2,23 +2,75 @@
|
||||
#ifndef _BMC150_ACCEL_H_
|
||||
#define _BMC150_ACCEL_H_
|
||||
|
||||
struct regmap;
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
enum {
|
||||
bmc150,
|
||||
bmi055,
|
||||
bma255,
|
||||
bma250e,
|
||||
bma222,
|
||||
bma222e,
|
||||
bma280,
|
||||
struct regmap;
|
||||
struct i2c_client;
|
||||
struct bmc150_accel_chip_info;
|
||||
struct bmc150_accel_interrupt_info;
|
||||
|
||||
struct bmc150_accel_interrupt {
|
||||
const struct bmc150_accel_interrupt_info *info;
|
||||
atomic_t users;
|
||||
};
|
||||
|
||||
struct bmc150_accel_trigger {
|
||||
struct bmc150_accel_data *data;
|
||||
struct iio_trigger *indio_trig;
|
||||
int (*setup)(struct bmc150_accel_trigger *t, bool state);
|
||||
int intr;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
enum bmc150_accel_interrupt_id {
|
||||
BMC150_ACCEL_INT_DATA_READY,
|
||||
BMC150_ACCEL_INT_ANY_MOTION,
|
||||
BMC150_ACCEL_INT_WATERMARK,
|
||||
BMC150_ACCEL_INTERRUPTS,
|
||||
};
|
||||
|
||||
enum bmc150_accel_trigger_id {
|
||||
BMC150_ACCEL_TRIGGER_DATA_READY,
|
||||
BMC150_ACCEL_TRIGGER_ANY_MOTION,
|
||||
BMC150_ACCEL_TRIGGERS,
|
||||
};
|
||||
|
||||
struct bmc150_accel_data {
|
||||
struct regmap *regmap;
|
||||
struct regulator_bulk_data regulators[2];
|
||||
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
|
||||
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
|
||||
struct mutex mutex;
|
||||
u8 fifo_mode, watermark;
|
||||
s16 buffer[8];
|
||||
/*
|
||||
* Ensure there is sufficient space and correct alignment for
|
||||
* the timestamp if enabled
|
||||
*/
|
||||
struct {
|
||||
__le16 channels[3];
|
||||
s64 ts __aligned(8);
|
||||
} scan;
|
||||
u8 bw_bits;
|
||||
u32 slope_dur;
|
||||
u32 slope_thres;
|
||||
u32 range;
|
||||
int ev_enable_state;
|
||||
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
|
||||
const struct bmc150_accel_chip_info *chip_info;
|
||||
struct i2c_client *second_device;
|
||||
void (*resume_callback)(struct device *dev);
|
||||
struct delayed_work resume_work;
|
||||
struct iio_mount_matrix orientation;
|
||||
};
|
||||
|
||||
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
const char *name, bool block_supported);
|
||||
int bmc150_accel_core_remove(struct device *dev);
|
||||
struct i2c_client *bmc150_get_second_device(struct i2c_client *second_device);
|
||||
void bmc150_set_second_device(struct i2c_client *second_device);
|
||||
extern const struct dev_pm_ops bmc150_accel_pm_ops;
|
||||
extern const struct regmap_config bmc150_regmap_conf;
|
||||
|
||||
|
@ -285,11 +285,17 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bmi088_accel_get_temp(data, val);
|
||||
goto out_read_raw_pm_put;
|
||||
case IIO_ACCEL:
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
goto out_read_raw_pm_put;
|
||||
@ -319,7 +325,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
|
||||
*val = BMI088_ACCEL_TEMP_UNIT;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_ACCEL:
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(data->regmap,
|
||||
BMI088_ACCEL_REG_ACC_RANGE, val);
|
||||
if (ret)
|
||||
@ -334,7 +343,10 @@ static int bmi088_accel_read_raw(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bmi088_accel_get_sample_freq(data, val, val2);
|
||||
goto out_read_raw_pm_put;
|
||||
default:
|
||||
@ -376,7 +388,10 @@ static int bmi088_accel_write_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bmi088_accel_set_sample_freq(data, val);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
@ -496,7 +511,6 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->channels = data->chip_info->channels;
|
||||
indio_dev->num_channels = data->chip_info->num_channels;
|
||||
indio_dev->name = name ? name : data->chip_info->name;
|
||||
@ -531,7 +545,6 @@ int bmi088_accel_core_remove(struct device *dev)
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
bmi088_accel_power_down(data);
|
||||
|
||||
return 0;
|
||||
|
968
drivers/iio/accel/fxls8962af-core.c
Normal file
968
drivers/iio/accel/fxls8962af-core.c
Normal file
@ -0,0 +1,968 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NXP FXLS8962AF/FXLS8964AF Accelerometer Core Driver
|
||||
*
|
||||
* Copyright 2021 Connected Cars A/S
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.nxp.com/docs/en/data-sheet/FXLS8962AF.pdf
|
||||
* https://www.nxp.com/docs/en/data-sheet/FXLS8964AF.pdf
|
||||
*
|
||||
* Errata:
|
||||
* https://www.nxp.com/docs/en/errata/ES_FXLS8962AF.pdf
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#include "fxls8962af.h"
|
||||
|
||||
#define FXLS8962AF_INT_STATUS 0x00
|
||||
#define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0)
|
||||
#define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5)
|
||||
#define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7)
|
||||
#define FXLS8962AF_TEMP_OUT 0x01
|
||||
#define FXLS8962AF_VECM_LSB 0x02
|
||||
#define FXLS8962AF_OUT_X_LSB 0x04
|
||||
#define FXLS8962AF_OUT_Y_LSB 0x06
|
||||
#define FXLS8962AF_OUT_Z_LSB 0x08
|
||||
#define FXLS8962AF_BUF_STATUS 0x0b
|
||||
#define FXLS8962AF_BUF_STATUS_BUF_CNT GENMASK(5, 0)
|
||||
#define FXLS8962AF_BUF_STATUS_BUF_OVF BIT(6)
|
||||
#define FXLS8962AF_BUF_STATUS_BUF_WMRK BIT(7)
|
||||
#define FXLS8962AF_BUF_X_LSB 0x0c
|
||||
#define FXLS8962AF_BUF_Y_LSB 0x0e
|
||||
#define FXLS8962AF_BUF_Z_LSB 0x10
|
||||
|
||||
#define FXLS8962AF_PROD_REV 0x12
|
||||
#define FXLS8962AF_WHO_AM_I 0x13
|
||||
|
||||
#define FXLS8962AF_SYS_MODE 0x14
|
||||
#define FXLS8962AF_SENS_CONFIG1 0x15
|
||||
#define FXLS8962AF_SENS_CONFIG1_ACTIVE BIT(0)
|
||||
#define FXLS8962AF_SENS_CONFIG1_RST BIT(7)
|
||||
#define FXLS8962AF_SC1_FSR_MASK GENMASK(2, 1)
|
||||
#define FXLS8962AF_SC1_FSR_PREP(x) FIELD_PREP(FXLS8962AF_SC1_FSR_MASK, (x))
|
||||
#define FXLS8962AF_SC1_FSR_GET(x) FIELD_GET(FXLS8962AF_SC1_FSR_MASK, (x))
|
||||
|
||||
#define FXLS8962AF_SENS_CONFIG2 0x16
|
||||
#define FXLS8962AF_SENS_CONFIG3 0x17
|
||||
#define FXLS8962AF_SC3_WAKE_ODR_MASK GENMASK(7, 4)
|
||||
#define FXLS8962AF_SC3_WAKE_ODR_PREP(x) FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x))
|
||||
#define FXLS8962AF_SC3_WAKE_ODR_GET(x) FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x))
|
||||
#define FXLS8962AF_SENS_CONFIG4 0x18
|
||||
#define FXLS8962AF_SC4_INT_PP_OD_MASK BIT(1)
|
||||
#define FXLS8962AF_SC4_INT_PP_OD_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_PP_OD_MASK, (x))
|
||||
#define FXLS8962AF_SC4_INT_POL_MASK BIT(0)
|
||||
#define FXLS8962AF_SC4_INT_POL_PREP(x) FIELD_PREP(FXLS8962AF_SC4_INT_POL_MASK, (x))
|
||||
#define FXLS8962AF_SENS_CONFIG5 0x19
|
||||
|
||||
#define FXLS8962AF_WAKE_IDLE_LSB 0x1b
|
||||
#define FXLS8962AF_SLEEP_IDLE_LSB 0x1c
|
||||
#define FXLS8962AF_ASLP_COUNT_LSB 0x1e
|
||||
|
||||
#define FXLS8962AF_INT_EN 0x20
|
||||
#define FXLS8962AF_INT_EN_BUF_EN BIT(6)
|
||||
#define FXLS8962AF_INT_PIN_SEL 0x21
|
||||
#define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0)
|
||||
#define FXLS8962AF_INT_PIN_SEL_INT1 0x00
|
||||
#define FXLS8962AF_INT_PIN_SEL_INT2 GENMASK(7, 0)
|
||||
|
||||
#define FXLS8962AF_OFF_X 0x22
|
||||
#define FXLS8962AF_OFF_Y 0x23
|
||||
#define FXLS8962AF_OFF_Z 0x24
|
||||
|
||||
#define FXLS8962AF_BUF_CONFIG1 0x26
|
||||
#define FXLS8962AF_BC1_BUF_MODE_MASK GENMASK(6, 5)
|
||||
#define FXLS8962AF_BC1_BUF_MODE_PREP(x) FIELD_PREP(FXLS8962AF_BC1_BUF_MODE_MASK, (x))
|
||||
#define FXLS8962AF_BUF_CONFIG2 0x27
|
||||
#define FXLS8962AF_BUF_CONFIG2_BUF_WMRK GENMASK(5, 0)
|
||||
|
||||
#define FXLS8962AF_ORIENT_STATUS 0x28
|
||||
#define FXLS8962AF_ORIENT_CONFIG 0x29
|
||||
#define FXLS8962AF_ORIENT_DBCOUNT 0x2a
|
||||
#define FXLS8962AF_ORIENT_BF_ZCOMP 0x2b
|
||||
#define FXLS8962AF_ORIENT_THS_REG 0x2c
|
||||
|
||||
#define FXLS8962AF_SDCD_INT_SRC1 0x2d
|
||||
#define FXLS8962AF_SDCD_INT_SRC2 0x2e
|
||||
#define FXLS8962AF_SDCD_CONFIG1 0x2f
|
||||
#define FXLS8962AF_SDCD_CONFIG2 0x30
|
||||
#define FXLS8962AF_SDCD_OT_DBCNT 0x31
|
||||
#define FXLS8962AF_SDCD_WT_DBCNT 0x32
|
||||
#define FXLS8962AF_SDCD_LTHS_LSB 0x33
|
||||
#define FXLS8962AF_SDCD_UTHS_LSB 0x35
|
||||
|
||||
#define FXLS8962AF_SELF_TEST_CONFIG1 0x37
|
||||
#define FXLS8962AF_SELF_TEST_CONFIG2 0x38
|
||||
|
||||
#define FXLS8962AF_MAX_REG 0x38
|
||||
|
||||
#define FXLS8962AF_DEVICE_ID 0x62
|
||||
#define FXLS8964AF_DEVICE_ID 0x84
|
||||
|
||||
/* Raw temp channel offset */
|
||||
#define FXLS8962AF_TEMP_CENTER_VAL 25
|
||||
|
||||
#define FXLS8962AF_AUTO_SUSPEND_DELAY_MS 2000
|
||||
|
||||
#define FXLS8962AF_FIFO_LENGTH 32
|
||||
#define FXLS8962AF_SCALE_TABLE_LEN 4
|
||||
#define FXLS8962AF_SAMP_FREQ_TABLE_LEN 13
|
||||
|
||||
static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = {
|
||||
{0, IIO_G_TO_M_S_2(980000)},
|
||||
{0, IIO_G_TO_M_S_2(1950000)},
|
||||
{0, IIO_G_TO_M_S_2(3910000)},
|
||||
{0, IIO_G_TO_M_S_2(7810000)},
|
||||
};
|
||||
|
||||
static const int fxls8962af_samp_freq_table[FXLS8962AF_SAMP_FREQ_TABLE_LEN][2] = {
|
||||
{3200, 0}, {1600, 0}, {800, 0}, {400, 0}, {200, 0}, {100, 0},
|
||||
{50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000},
|
||||
{1, 563000}, {0, 781000},
|
||||
};
|
||||
|
||||
struct fxls8962af_chip_info {
|
||||
const char *name;
|
||||
const struct iio_chan_spec *channels;
|
||||
int num_channels;
|
||||
u8 chip_id;
|
||||
};
|
||||
|
||||
struct fxls8962af_data {
|
||||
struct regmap *regmap;
|
||||
const struct fxls8962af_chip_info *chip_info;
|
||||
struct regulator *vdd_reg;
|
||||
struct {
|
||||
__le16 channels[3];
|
||||
s64 ts __aligned(8);
|
||||
} scan;
|
||||
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
|
||||
struct iio_mount_matrix orientation;
|
||||
u8 watermark;
|
||||
};
|
||||
|
||||
const struct regmap_config fxls8962af_regmap_conf = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = FXLS8962AF_MAX_REG,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fxls8962af_regmap_conf);
|
||||
|
||||
enum {
|
||||
fxls8962af_idx_x,
|
||||
fxls8962af_idx_y,
|
||||
fxls8962af_idx_z,
|
||||
fxls8962af_idx_ts,
|
||||
};
|
||||
|
||||
enum fxls8962af_int_pin {
|
||||
FXLS8962AF_PIN_INT1,
|
||||
FXLS8962AF_PIN_INT2,
|
||||
};
|
||||
|
||||
static int fxls8962af_power_on(struct fxls8962af_data *data)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to power on\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxls8962af_power_off(struct fxls8962af_data *data)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
ret = pm_runtime_put_autosuspend(dev);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to power off\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxls8962af_standby(struct fxls8962af_data *data)
|
||||
{
|
||||
return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
|
||||
FXLS8962AF_SENS_CONFIG1_ACTIVE, 0);
|
||||
}
|
||||
|
||||
static int fxls8962af_active(struct fxls8962af_data *data)
|
||||
{
|
||||
return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
|
||||
FXLS8962AF_SENS_CONFIG1_ACTIVE, 1);
|
||||
}
|
||||
|
||||
static int fxls8962af_is_active(struct fxls8962af_data *data)
|
||||
{
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return reg & FXLS8962AF_SENS_CONFIG1_ACTIVE;
|
||||
}
|
||||
|
||||
static int fxls8962af_get_out(struct fxls8962af_data *data,
|
||||
struct iio_chan_spec const *chan, int *val)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
__le16 raw_val;
|
||||
int is_active;
|
||||
int ret;
|
||||
|
||||
is_active = fxls8962af_is_active(data);
|
||||
if (!is_active) {
|
||||
ret = fxls8962af_power_on(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, chan->address,
|
||||
&raw_val, (chan->scan_type.storagebits / 8));
|
||||
|
||||
if (!is_active)
|
||||
fxls8962af_power_off(data);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to get out reg 0x%lx\n", chan->address);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = sign_extend32(le16_to_cpu(raw_val),
|
||||
chan->scan_type.realbits - 1);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int fxls8962af_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:
|
||||
*type = IIO_VAL_INT_PLUS_NANO;
|
||||
*vals = (int *)fxls8962af_scale_table;
|
||||
*length = ARRAY_SIZE(fxls8962af_scale_table) * 2;
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
*vals = (int *)fxls8962af_samp_freq_table;
|
||||
*length = ARRAY_SIZE(fxls8962af_samp_freq_table) * 2;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
}
|
||||
|
||||
static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg,
|
||||
u8 mask, u8 val)
|
||||
{
|
||||
int ret;
|
||||
int is_active;
|
||||
|
||||
is_active = fxls8962af_is_active(data);
|
||||
if (is_active) {
|
||||
ret = fxls8962af_standby(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, reg, mask, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is_active) {
|
||||
ret = fxls8962af_active(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fxls8962af_set_full_scale(struct fxls8962af_data *data, u32 scale)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fxls8962af_scale_table); i++)
|
||||
if (scale == fxls8962af_scale_table[i][1])
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(fxls8962af_scale_table))
|
||||
return -EINVAL;
|
||||
|
||||
return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG1,
|
||||
FXLS8962AF_SC1_FSR_MASK,
|
||||
FXLS8962AF_SC1_FSR_PREP(i));
|
||||
}
|
||||
|
||||
static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data,
|
||||
int *val)
|
||||
{
|
||||
int ret;
|
||||
unsigned int reg;
|
||||
u8 range_idx;
|
||||
|
||||
ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
range_idx = FXLS8962AF_SC1_FSR_GET(reg);
|
||||
|
||||
*val = fxls8962af_scale_table[range_idx][1];
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
|
||||
static int fxls8962af_set_samp_freq(struct fxls8962af_data *data, u32 val,
|
||||
u32 val2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fxls8962af_samp_freq_table); i++)
|
||||
if (val == fxls8962af_samp_freq_table[i][0] &&
|
||||
val2 == fxls8962af_samp_freq_table[i][1])
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(fxls8962af_samp_freq_table))
|
||||
return -EINVAL;
|
||||
|
||||
return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG3,
|
||||
FXLS8962AF_SC3_WAKE_ODR_MASK,
|
||||
FXLS8962AF_SC3_WAKE_ODR_PREP(i));
|
||||
}
|
||||
|
||||
static unsigned int fxls8962af_read_samp_freq(struct fxls8962af_data *data,
|
||||
int *val, int *val2)
|
||||
{
|
||||
int ret;
|
||||
unsigned int reg;
|
||||
u8 range_idx;
|
||||
|
||||
ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG3, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
range_idx = FXLS8962AF_SC3_WAKE_ODR_GET(reg);
|
||||
|
||||
*val = fxls8962af_samp_freq_table[range_idx][0];
|
||||
*val2 = fxls8962af_samp_freq_table[range_idx][1];
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
static int fxls8962af_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
case IIO_ACCEL:
|
||||
return fxls8962af_get_out(data, chan, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
if (chan->type != IIO_TEMP)
|
||||
return -EINVAL;
|
||||
|
||||
*val = FXLS8962AF_TEMP_CENTER_VAL;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
return fxls8962af_read_full_scale(data, val2);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return fxls8962af_read_samp_freq(data, val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int fxls8962af_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = fxls8962af_set_full_scale(data, val2);
|
||||
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = fxls8962af_set_samp_freq(data, val, val2);
|
||||
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
return ret;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (val > FXLS8962AF_FIFO_LENGTH)
|
||||
val = FXLS8962AF_FIFO_LENGTH;
|
||||
|
||||
data->watermark = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FXLS8962AF_CHANNEL(axis, reg, idx) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
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 = idx, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define FXLS8962AF_TEMP_CHANNEL { \
|
||||
.type = IIO_TEMP, \
|
||||
.address = FXLS8962AF_TEMP_OUT, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET),\
|
||||
.scan_index = -1, \
|
||||
.scan_type = { \
|
||||
.realbits = 8, \
|
||||
.storagebits = 8, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec fxls8962af_channels[] = {
|
||||
FXLS8962AF_CHANNEL(X, FXLS8962AF_OUT_X_LSB, fxls8962af_idx_x),
|
||||
FXLS8962AF_CHANNEL(Y, FXLS8962AF_OUT_Y_LSB, fxls8962af_idx_y),
|
||||
FXLS8962AF_CHANNEL(Z, FXLS8962AF_OUT_Z_LSB, fxls8962af_idx_z),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(fxls8962af_idx_ts),
|
||||
FXLS8962AF_TEMP_CHANNEL,
|
||||
};
|
||||
|
||||
static const struct fxls8962af_chip_info fxls_chip_info_table[] = {
|
||||
[fxls8962af] = {
|
||||
.chip_id = FXLS8962AF_DEVICE_ID,
|
||||
.name = "fxls8962af",
|
||||
.channels = fxls8962af_channels,
|
||||
.num_channels = ARRAY_SIZE(fxls8962af_channels),
|
||||
},
|
||||
[fxls8964af] = {
|
||||
.chip_id = FXLS8964AF_DEVICE_ID,
|
||||
.name = "fxls8964af",
|
||||
.channels = fxls8962af_channels,
|
||||
.num_channels = ARRAY_SIZE(fxls8962af_channels),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info fxls8962af_info = {
|
||||
.read_raw = &fxls8962af_read_raw,
|
||||
.write_raw = &fxls8962af_write_raw,
|
||||
.write_raw_get_fmt = fxls8962af_write_raw_get_fmt,
|
||||
.read_avail = fxls8962af_read_avail,
|
||||
.hwfifo_set_watermark = fxls8962af_set_watermark,
|
||||
};
|
||||
|
||||
static int fxls8962af_reset(struct fxls8962af_data *data)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
|
||||
FXLS8962AF_SENS_CONFIG1_RST,
|
||||
FXLS8962AF_SENS_CONFIG1_RST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* TBOOT1, TBOOT2, specifies we have to wait between 1 - 17.7ms */
|
||||
ret = regmap_read_poll_timeout(data->regmap, FXLS8962AF_INT_STATUS, reg,
|
||||
(reg & FXLS8962AF_INT_STATUS_SRC_BOOT),
|
||||
1000, 18000);
|
||||
if (ret == -ETIMEDOUT)
|
||||
dev_err(dev, "reset timeout, int_status = 0x%x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __fxls8962af_fifo_set_mode(struct fxls8962af_data *data, bool onoff)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Enable watermark at max fifo size */
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG2,
|
||||
FXLS8962AF_BUF_CONFIG2_BUF_WMRK,
|
||||
data->watermark);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG1,
|
||||
FXLS8962AF_BC1_BUF_MODE_MASK,
|
||||
FXLS8962AF_BC1_BUF_MODE_PREP(onoff));
|
||||
}
|
||||
|
||||
static int fxls8962af_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
return fxls8962af_power_on(iio_priv(indio_dev));
|
||||
}
|
||||
|
||||
static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
fxls8962af_standby(data);
|
||||
|
||||
/* Enable buffer interrupt */
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
|
||||
FXLS8962AF_INT_EN_BUF_EN,
|
||||
FXLS8962AF_INT_EN_BUF_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __fxls8962af_fifo_set_mode(data, true);
|
||||
|
||||
fxls8962af_active(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
fxls8962af_standby(data);
|
||||
|
||||
/* Disable buffer interrupt */
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
|
||||
FXLS8962AF_INT_EN_BUF_EN, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __fxls8962af_fifo_set_mode(data, false);
|
||||
|
||||
fxls8962af_active(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
|
||||
return fxls8962af_power_off(data);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = {
|
||||
.preenable = fxls8962af_buffer_preenable,
|
||||
.postenable = fxls8962af_buffer_postenable,
|
||||
.predisable = fxls8962af_buffer_predisable,
|
||||
.postdisable = fxls8962af_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int fxls8962af_i2c_raw_read_errata3(struct fxls8962af_data *data,
|
||||
u16 *buffer, int samples,
|
||||
int sample_length)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB,
|
||||
&buffer[i * 3], sample_length);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxls8962af_fifo_transfer(struct fxls8962af_data *data,
|
||||
u16 *buffer, int samples)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int sample_length = 3 * sizeof(*buffer);
|
||||
int total_length = samples * sample_length;
|
||||
int ret;
|
||||
|
||||
if (i2c_verify_client(dev))
|
||||
/*
|
||||
* Due to errata bug:
|
||||
* E3: FIFO burst read operation error using I2C interface
|
||||
* We have to avoid burst reads on I2C..
|
||||
*/
|
||||
ret = fxls8962af_i2c_raw_read_errata3(data, buffer, samples,
|
||||
sample_length);
|
||||
else
|
||||
ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer,
|
||||
total_length);
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "Error transferring data from fifo: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
u16 buffer[FXLS8962AF_FIFO_LENGTH * 3];
|
||||
uint64_t sample_period;
|
||||
unsigned int reg;
|
||||
int64_t tstamp;
|
||||
int ret, i;
|
||||
u8 count;
|
||||
|
||||
ret = regmap_read(data->regmap, FXLS8962AF_BUF_STATUS, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) {
|
||||
dev_err(dev, "Buffer overflow");
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
count = reg & FXLS8962AF_BUF_STATUS_BUF_CNT;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
data->old_timestamp = data->timestamp;
|
||||
data->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
/*
|
||||
* Approximate timestamps for each of the sample based on the sampling,
|
||||
* frequency, timestamp for last sample and number of samples.
|
||||
*/
|
||||
sample_period = (data->timestamp - data->old_timestamp);
|
||||
do_div(sample_period, count);
|
||||
tstamp = data->timestamp - (count - 1) * sample_period;
|
||||
|
||||
ret = fxls8962af_fifo_transfer(data, buffer, count);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Demux hw FIFO into kfifo. */
|
||||
for (i = 0; i < count; i++) {
|
||||
int j, bit;
|
||||
|
||||
j = 0;
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
|
||||
sizeof(data->scan.channels[0]));
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
tstamp);
|
||||
|
||||
tstamp += sample_period;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static irqreturn_t fxls8962af_interrupt(int irq, void *p)
|
||||
{
|
||||
struct iio_dev *indio_dev = p;
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, FXLS8962AF_INT_STATUS, ®);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) {
|
||||
ret = fxls8962af_fifo_flush(indio_dev);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static void fxls8962af_regulator_disable(void *data_ptr)
|
||||
{
|
||||
struct fxls8962af_data *data = data_ptr;
|
||||
|
||||
regulator_disable(data->vdd_reg);
|
||||
}
|
||||
|
||||
static void fxls8962af_pm_disable(void *dev_ptr)
|
||||
{
|
||||
struct device *dev = dev_ptr;
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_put_noidle(dev);
|
||||
|
||||
fxls8962af_standby(iio_priv(indio_dev));
|
||||
}
|
||||
|
||||
static void fxls8962af_get_irq(struct device_node *of_node,
|
||||
enum fxls8962af_int_pin *pin)
|
||||
{
|
||||
int irq;
|
||||
|
||||
irq = of_irq_get_byname(of_node, "INT2");
|
||||
if (irq > 0) {
|
||||
*pin = FXLS8962AF_PIN_INT2;
|
||||
return;
|
||||
}
|
||||
|
||||
*pin = FXLS8962AF_PIN_INT1;
|
||||
}
|
||||
|
||||
static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
unsigned long irq_type;
|
||||
bool irq_active_high;
|
||||
enum fxls8962af_int_pin int_pin;
|
||||
u8 int_pin_sel;
|
||||
int ret;
|
||||
|
||||
fxls8962af_get_irq(dev->of_node, &int_pin);
|
||||
switch (int_pin) {
|
||||
case FXLS8962AF_PIN_INT1:
|
||||
int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1;
|
||||
break;
|
||||
case FXLS8962AF_PIN_INT2:
|
||||
int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT2;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported int pin selected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_PIN_SEL,
|
||||
FXLS8962AF_INT_PIN_SEL_MASK, int_pin_sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
irq_type = irqd_get_trigger_type(irq_get_irq_data(irq));
|
||||
|
||||
switch (irq_type) {
|
||||
case IRQF_TRIGGER_HIGH:
|
||||
case IRQF_TRIGGER_RISING:
|
||||
irq_active_high = true;
|
||||
break;
|
||||
case IRQF_TRIGGER_LOW:
|
||||
case IRQF_TRIGGER_FALLING:
|
||||
irq_active_high = false;
|
||||
break;
|
||||
default:
|
||||
dev_info(dev, "mode %lx unsupported\n", irq_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4,
|
||||
FXLS8962AF_SC4_INT_POL_MASK,
|
||||
FXLS8962AF_SC4_INT_POL_PREP(irq_active_high));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (device_property_read_bool(dev, "drive-open-drain")) {
|
||||
ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4,
|
||||
FXLS8962AF_SC4_INT_PP_OD_MASK,
|
||||
FXLS8962AF_SC4_INT_PP_OD_PREP(1));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
irq_type |= IRQF_SHARED;
|
||||
}
|
||||
|
||||
return devm_request_threaded_irq(dev,
|
||||
irq,
|
||||
NULL, fxls8962af_interrupt,
|
||||
irq_type | IRQF_ONESHOT,
|
||||
indio_dev->name, indio_dev);
|
||||
}
|
||||
|
||||
int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
|
||||
{
|
||||
struct fxls8962af_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
unsigned int reg;
|
||||
int ret, i;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
dev_set_drvdata(dev, indio_dev);
|
||||
data->regmap = regmap;
|
||||
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->vdd_reg = devm_regulator_get(dev, "vdd");
|
||||
if (IS_ERR(data->vdd_reg))
|
||||
return dev_err_probe(dev, PTR_ERR(data->vdd_reg),
|
||||
"Failed to get vdd regulator\n");
|
||||
|
||||
ret = regulator_enable(data->vdd_reg);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable vdd regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(dev, fxls8962af_regulator_disable, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fxls_chip_info_table); i++) {
|
||||
if (fxls_chip_info_table[i].chip_id == reg) {
|
||||
data->chip_info = &fxls_chip_info_table[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(fxls_chip_info_table)) {
|
||||
dev_err(dev, "failed to match device in table\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
indio_dev->channels = data->chip_info->channels;
|
||||
indio_dev->num_channels = data->chip_info->num_channels;
|
||||
indio_dev->name = data->chip_info->name;
|
||||
indio_dev->info = &fxls8962af_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = fxls8962af_reset(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (irq) {
|
||||
ret = fxls8962af_irq_setup(indio_dev, irq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
|
||||
INDIO_BUFFER_SOFTWARE,
|
||||
&fxls8962af_buffer_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pm_runtime_set_active(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, FXLS8962AF_AUTO_SUSPEND_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, fxls8962af_pm_disable, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fxls8962af_core_probe);
|
||||
|
||||
static int __maybe_unused fxls8962af_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
int ret;
|
||||
|
||||
ret = fxls8962af_standby(data);
|
||||
if (ret) {
|
||||
dev_err(dev, "powering off device failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused fxls8962af_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
|
||||
|
||||
return fxls8962af_active(data);
|
||||
}
|
||||
|
||||
const struct dev_pm_ops fxls8962af_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
|
||||
fxls8962af_runtime_resume, NULL)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fxls8962af_pm_ops);
|
||||
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
|
||||
MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver");
|
||||
MODULE_LICENSE("GPL v2");
|
57
drivers/iio/accel/fxls8962af-i2c.c
Normal file
57
drivers/iio/accel/fxls8962af-i2c.c
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NXP FXLS8962AF/FXLS8964AF Accelerometer I2C Driver
|
||||
*
|
||||
* Copyright 2021 Connected Cars A/S
|
||||
*/
|
||||
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "fxls8962af.h"
|
||||
|
||||
static int fxls8962af_probe(struct i2c_client *client)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &fxls8962af_regmap_conf);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "Failed to initialize i2c regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return fxls8962af_core_probe(&client->dev, regmap, client->irq);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id fxls8962af_id[] = {
|
||||
{ "fxls8962af", fxls8962af },
|
||||
{ "fxls8964af", fxls8964af },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fxls8962af_id);
|
||||
|
||||
static const struct of_device_id fxls8962af_of_match[] = {
|
||||
{ .compatible = "nxp,fxls8962af" },
|
||||
{ .compatible = "nxp,fxls8964af" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fxls8962af_of_match);
|
||||
|
||||
static struct i2c_driver fxls8962af_driver = {
|
||||
.driver = {
|
||||
.name = "fxls8962af_i2c",
|
||||
.of_match_table = fxls8962af_of_match,
|
||||
.pm = &fxls8962af_pm_ops,
|
||||
},
|
||||
.probe_new = fxls8962af_probe,
|
||||
.id_table = fxls8962af_id,
|
||||
};
|
||||
module_i2c_driver(fxls8962af_driver);
|
||||
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
|
||||
MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer i2c driver");
|
||||
MODULE_LICENSE("GPL v2");
|
57
drivers/iio/accel/fxls8962af-spi.c
Normal file
57
drivers/iio/accel/fxls8962af-spi.c
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NXP FXLS8962AF/FXLS8964AF Accelerometer SPI Driver
|
||||
*
|
||||
* Copyright 2021 Connected Cars A/S
|
||||
*/
|
||||
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "fxls8962af.h"
|
||||
|
||||
static int fxls8962af_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &fxls8962af_regmap_conf);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "Failed to initialize spi regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return fxls8962af_core_probe(&spi->dev, regmap, spi->irq);
|
||||
}
|
||||
|
||||
static const struct of_device_id fxls8962af_spi_of_match[] = {
|
||||
{ .compatible = "nxp,fxls8962af" },
|
||||
{ .compatible = "nxp,fxls8964af" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fxls8962af_spi_of_match);
|
||||
|
||||
static const struct spi_device_id fxls8962af_spi_id_table[] = {
|
||||
{ "fxls8962af", fxls8962af },
|
||||
{ "fxls8964af", fxls8964af },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, fxls8962af_spi_id_table);
|
||||
|
||||
static struct spi_driver fxls8962af_driver = {
|
||||
.driver = {
|
||||
.name = "fxls8962af_spi",
|
||||
.pm = &fxls8962af_pm_ops,
|
||||
.of_match_table = fxls8962af_spi_of_match,
|
||||
},
|
||||
.probe = fxls8962af_probe,
|
||||
.id_table = fxls8962af_spi_id_table,
|
||||
};
|
||||
module_spi_driver(fxls8962af_driver);
|
||||
|
||||
MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
|
||||
MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer spi driver");
|
||||
MODULE_LICENSE("GPL v2");
|
22
drivers/iio/accel/fxls8962af.h
Normal file
22
drivers/iio/accel/fxls8962af.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright 2021 Connected Cars A/S
|
||||
*/
|
||||
#ifndef _FXLS8962AF_H_
|
||||
#define _FXLS8962AF_H_
|
||||
|
||||
struct regmap;
|
||||
struct device;
|
||||
|
||||
enum {
|
||||
fxls8962af,
|
||||
fxls8964af,
|
||||
};
|
||||
|
||||
int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq);
|
||||
int fxls8962af_core_remove(struct device *dev);
|
||||
|
||||
extern const struct dev_pm_ops fxls8962af_pm_ops;
|
||||
extern const struct regmap_config fxls8962af_regmap_conf;
|
||||
|
||||
#endif /* _FXLS8962AF_H_ */
|
@ -6,13 +6,10 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include "../common/hid-sensors/hid-sensor-trigger.h"
|
||||
|
||||
@ -28,8 +25,11 @@ struct accel_3d_state {
|
||||
struct hid_sensor_hub_callbacks callbacks;
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
|
||||
/* Reserve for 3 channels + padding + timestamp */
|
||||
u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3];
|
||||
/* Ensure timestamp is naturally aligned */
|
||||
struct {
|
||||
u32 accel_val[3];
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
@ -245,8 +245,8 @@ static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
accel_state->timestamp = iio_get_time_ns(indio_dev);
|
||||
|
||||
hid_sensor_push_data(indio_dev,
|
||||
accel_state->accel_val,
|
||||
sizeof(accel_state->accel_val),
|
||||
&accel_state->scan,
|
||||
sizeof(accel_state->scan),
|
||||
accel_state->timestamp);
|
||||
|
||||
accel_state->timestamp = 0;
|
||||
@ -271,7 +271,7 @@ static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
|
||||
case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
|
||||
case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
|
||||
offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
|
||||
accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] =
|
||||
accel_state->scan.accel_val[CHANNEL_SCAN_INDEX_X + offset] =
|
||||
*(u32 *)raw_data;
|
||||
ret = 0;
|
||||
break;
|
||||
@ -462,3 +462,4 @@ module_platform_driver(hid_accel_3d_platform_driver);
|
||||
MODULE_DESCRIPTION("HID Sensor Accel 3D");
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(IIO_HID);
|
||||
|
@ -51,13 +51,15 @@
|
||||
#define KXTF9_REG_TILT_POS_CUR 0x10
|
||||
#define KXTF9_REG_TILT_POS_PREV 0x11
|
||||
#define KXTF9_REG_INT_SRC1 0x15
|
||||
#define KXCJK1013_REG_INT_SRC1 0x16 /* compatible, but called INT_SRC2 in KXTF9 ds */
|
||||
#define KXTF9_REG_INT_SRC2 0x16
|
||||
#define KXCJK1013_REG_INT_SRC1 0x16
|
||||
#define KXCJK1013_REG_INT_SRC2 0x17
|
||||
#define KXCJK1013_REG_STATUS_REG 0x18
|
||||
#define KXCJK1013_REG_INT_REL 0x1A
|
||||
#define KXCJK1013_REG_CTRL1 0x1B
|
||||
#define KXTF9_REG_CTRL2 0x1C
|
||||
#define KXCJK1013_REG_CTRL2 0x1D /* mostly compatible, CTRL_REG3 in KTXF9 ds */
|
||||
#define KXTF9_REG_CTRL3 0x1D
|
||||
#define KXCJK1013_REG_CTRL2 0x1D
|
||||
#define KXCJK1013_REG_INT_CTRL1 0x1E
|
||||
#define KXCJK1013_REG_INT_CTRL2 0x1F
|
||||
#define KXTF9_REG_INT_CTRL3 0x20
|
||||
@ -77,6 +79,45 @@
|
||||
#define KXTF9_REG_HYST_SET 0x5F
|
||||
#define KXCJK1013_REG_WAKE_THRES 0x6A
|
||||
|
||||
/* Everything up to 0x11 is equal to KXCJK1013/KXTF9 above */
|
||||
#define KX023_REG_INS1 0x12
|
||||
#define KX023_REG_INS2 0x13
|
||||
#define KX023_REG_INS3 0x14
|
||||
#define KX023_REG_STAT 0x15
|
||||
#define KX023_REG_INT_REL 0x17
|
||||
#define KX023_REG_CNTL1 0x18
|
||||
#define KX023_REG_CNTL2 0x19
|
||||
#define KX023_REG_CNTL3 0x1A
|
||||
#define KX023_REG_ODCNTL 0x1B
|
||||
#define KX023_REG_INC1 0x1C
|
||||
#define KX023_REG_INC2 0x1D
|
||||
#define KX023_REG_INC3 0x1E
|
||||
#define KX023_REG_INC4 0x1F
|
||||
#define KX023_REG_INC5 0x20
|
||||
#define KX023_REG_INC6 0x21
|
||||
#define KX023_REG_TILT_TIMER 0x22
|
||||
#define KX023_REG_WUFC 0x23
|
||||
#define KX023_REG_TDTRC 0x24
|
||||
#define KX023_REG_TDTC 0x25
|
||||
#define KX023_REG_TTH 0x26
|
||||
#define KX023_REG_TTL 0x27
|
||||
#define KX023_REG_FTD 0x28
|
||||
#define KX023_REG_STD 0x29
|
||||
#define KX023_REG_TLT 0x2A
|
||||
#define KX023_REG_TWS 0x2B
|
||||
#define KX023_REG_ATH 0x30
|
||||
#define KX023_REG_TILT_ANGLE_LL 0x32
|
||||
#define KX023_REG_TILT_ANGLE_HL 0x33
|
||||
#define KX023_REG_HYST_SET 0x34
|
||||
#define KX023_REG_LP_CNTL 0x35
|
||||
#define KX023_REG_BUF_CNTL1 0x3A
|
||||
#define KX023_REG_BUF_CNTL2 0x3B
|
||||
#define KX023_REG_BUF_STATUS_1 0x3C
|
||||
#define KX023_REG_BUF_STATUS_2 0x3D
|
||||
#define KX023_REG_BUF_CLEAR 0x3E
|
||||
#define KX023_REG_BUF_READ 0x3F
|
||||
#define KX023_REG_SELF_TEST 0x60
|
||||
|
||||
#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_RES BIT(6)
|
||||
#define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5)
|
||||
@ -117,6 +158,14 @@
|
||||
#define KXCJK1013_REG_INT_SRC2_BIT_XP BIT(4)
|
||||
#define KXCJK1013_REG_INT_SRC2_BIT_XN BIT(5)
|
||||
|
||||
/* KX023 interrupt routing to INT1. INT2 can be configured with INC6 */
|
||||
#define KX023_REG_INC4_BFI1 BIT(6)
|
||||
#define KX023_REG_INC4_WMI1 BIT(5)
|
||||
#define KX023_REG_INC4_DRDY1 BIT(4)
|
||||
#define KX023_REG_INC4_TDTI1 BIT(2)
|
||||
#define KX023_REG_INC4_WUFI1 BIT(1)
|
||||
#define KX023_REG_INC4_TPI1 BIT(0)
|
||||
|
||||
#define KXCJK1013_DEFAULT_WAKE_THRES 1
|
||||
|
||||
enum kx_chipset {
|
||||
@ -124,6 +173,7 @@ enum kx_chipset {
|
||||
KXCJ91008,
|
||||
KXTJ21009,
|
||||
KXTF9,
|
||||
KX0231025,
|
||||
KX_MAX_CHIPS /* this must be last */
|
||||
};
|
||||
|
||||
@ -133,6 +183,63 @@ enum kx_acpi_type {
|
||||
ACPI_KIOX010A,
|
||||
};
|
||||
|
||||
struct kx_chipset_regs {
|
||||
u8 int_src1;
|
||||
u8 int_src2;
|
||||
u8 int_rel;
|
||||
u8 ctrl1;
|
||||
u8 wuf_ctrl;
|
||||
u8 int_ctrl1;
|
||||
u8 data_ctrl;
|
||||
u8 wake_timer;
|
||||
u8 wake_thres;
|
||||
};
|
||||
|
||||
static const struct kx_chipset_regs kxcjk1013_regs = {
|
||||
.int_src1 = KXCJK1013_REG_INT_SRC1,
|
||||
.int_src2 = KXCJK1013_REG_INT_SRC2,
|
||||
.int_rel = KXCJK1013_REG_INT_REL,
|
||||
.ctrl1 = KXCJK1013_REG_CTRL1,
|
||||
.wuf_ctrl = KXCJK1013_REG_CTRL2,
|
||||
.int_ctrl1 = KXCJK1013_REG_INT_CTRL1,
|
||||
.data_ctrl = KXCJK1013_REG_DATA_CTRL,
|
||||
.wake_timer = KXCJK1013_REG_WAKE_TIMER,
|
||||
.wake_thres = KXCJK1013_REG_WAKE_THRES,
|
||||
};
|
||||
|
||||
static const struct kx_chipset_regs kxtf9_regs = {
|
||||
/* .int_src1 was moved to INT_SRC2 on KXTF9 */
|
||||
.int_src1 = KXTF9_REG_INT_SRC2,
|
||||
/* .int_src2 is not available */
|
||||
.int_rel = KXCJK1013_REG_INT_REL,
|
||||
.ctrl1 = KXCJK1013_REG_CTRL1,
|
||||
.wuf_ctrl = KXTF9_REG_CTRL3,
|
||||
.int_ctrl1 = KXCJK1013_REG_INT_CTRL1,
|
||||
.data_ctrl = KXCJK1013_REG_DATA_CTRL,
|
||||
.wake_timer = KXCJK1013_REG_WAKE_TIMER,
|
||||
.wake_thres = KXTF9_REG_WAKE_THRESH,
|
||||
};
|
||||
|
||||
/* The registers have totally different names but the bits are compatible */
|
||||
static const struct kx_chipset_regs kx0231025_regs = {
|
||||
.int_src1 = KX023_REG_INS2,
|
||||
.int_src2 = KX023_REG_INS3,
|
||||
.int_rel = KX023_REG_INT_REL,
|
||||
.ctrl1 = KX023_REG_CNTL1,
|
||||
.wuf_ctrl = KX023_REG_CNTL3,
|
||||
.int_ctrl1 = KX023_REG_INC1,
|
||||
.data_ctrl = KX023_REG_ODCNTL,
|
||||
.wake_timer = KX023_REG_WUFC,
|
||||
.wake_thres = KX023_REG_ATH,
|
||||
};
|
||||
|
||||
enum kxcjk1013_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_MAX
|
||||
};
|
||||
|
||||
struct kxcjk1013_data {
|
||||
struct regulator_bulk_data regulators[2];
|
||||
struct i2c_client *client;
|
||||
@ -140,7 +247,11 @@ struct kxcjk1013_data {
|
||||
struct iio_trigger *motion_trig;
|
||||
struct iio_mount_matrix orientation;
|
||||
struct mutex mutex;
|
||||
s16 buffer[8];
|
||||
/* Ensure timestamp naturally aligned */
|
||||
struct {
|
||||
s16 chans[AXIS_MAX];
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
u8 odr_bits;
|
||||
u8 range;
|
||||
int wake_thres;
|
||||
@ -152,13 +263,7 @@ struct kxcjk1013_data {
|
||||
int64_t timestamp;
|
||||
enum kx_chipset chipset;
|
||||
enum kx_acpi_type acpi_type;
|
||||
};
|
||||
|
||||
enum kxcjk1013_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_MAX,
|
||||
const struct kx_chipset_regs *regs;
|
||||
};
|
||||
|
||||
enum kxcjk1013_mode {
|
||||
@ -268,6 +373,22 @@ static const struct {
|
||||
{0x05, 5100},
|
||||
{0x06, 2700},
|
||||
},
|
||||
/* KX023-1025 */
|
||||
{
|
||||
/* First 4 are not in datasheet, taken from KXCTJ2-1009 */
|
||||
{0x08, 1240000},
|
||||
{0x09, 621000},
|
||||
{0x0A, 309000},
|
||||
{0x0B, 151000},
|
||||
{0, 81000},
|
||||
{0x01, 40000},
|
||||
{0x02, 22000},
|
||||
{0x03, 12000},
|
||||
{0x04, 7000},
|
||||
{0x05, 4400},
|
||||
{0x06, 3000},
|
||||
{0x07, 3000},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct {
|
||||
@ -309,7 +430,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -320,8 +441,7 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
|
||||
else
|
||||
ret |= KXCJK1013_REG_CTRL1_BIT_PC1;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_CTRL1, ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -335,7 +455,7 @@ static int kxcjk1013_get_mode(struct kxcjk1013_data *data,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -353,7 +473,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -364,9 +484,7 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index)
|
||||
ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3);
|
||||
ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_CTRL1,
|
||||
ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -400,7 +518,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -409,8 +527,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
/* Set 12 bit mode */
|
||||
ret |= KXCJK1013_REG_CTRL1_BIT_RES;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1,
|
||||
ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl\n");
|
||||
return ret;
|
||||
@ -421,7 +538,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->data_ctrl);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_data_ctrl\n");
|
||||
return ret;
|
||||
@ -430,7 +547,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
data->odr_bits = ret;
|
||||
|
||||
/* Set up INT polarity */
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
|
||||
return ret;
|
||||
@ -441,13 +558,23 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
|
||||
ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* On KX023, route all used interrupts to INT1 for now */
|
||||
if (data->chipset == KX0231025 && data->client->irq > 0) {
|
||||
ret = i2c_smbus_write_byte_data(data->client, KX023_REG_INC4,
|
||||
KX023_REG_INC4_DRDY1 |
|
||||
KX023_REG_INC4_WUFI1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_inc4\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = kxcjk1013_set_mode(data, OPERATION);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -478,7 +605,7 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
|
||||
int ret;
|
||||
|
||||
if (on)
|
||||
ret = pm_runtime_get_sync(&data->client->dev);
|
||||
ret = pm_runtime_resume_and_get(&data->client->dev);
|
||||
else {
|
||||
pm_runtime_mark_last_busy(&data->client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&data->client->dev);
|
||||
@ -486,8 +613,6 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
"Failed: %s for %d\n", __func__, on);
|
||||
if (on)
|
||||
pm_runtime_put_noidle(&data->client->dev);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@ -497,10 +622,9 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
|
||||
|
||||
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
|
||||
{
|
||||
int waketh_reg, ret;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_WAKE_TIMER,
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_timer,
|
||||
data->wake_dur);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev,
|
||||
@ -508,9 +632,7 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
waketh_reg = data->chipset == KXTF9 ?
|
||||
KXTF9_REG_WAKE_THRESH : KXCJK1013_REG_WAKE_THRES;
|
||||
ret = i2c_smbus_write_byte_data(data->client, waketh_reg,
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->wake_thres,
|
||||
data->wake_thres);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_wake_thres\n");
|
||||
@ -539,7 +661,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
|
||||
return ret;
|
||||
@ -550,14 +672,13 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
|
||||
ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -568,8 +689,7 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_CTRL1, ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -599,7 +719,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
|
||||
return ret;
|
||||
@ -610,14 +730,13 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
|
||||
ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->int_ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -628,8 +747,7 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
|
||||
else
|
||||
ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client,
|
||||
KXCJK1013_REG_CTRL1, ret);
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->ctrl1, ret);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
||||
return ret;
|
||||
@ -701,7 +819,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL,
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->data_ctrl,
|
||||
odr_setting->odr_bits);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing data_ctrl\n");
|
||||
@ -710,7 +828,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
|
||||
|
||||
data->odr_bits = odr_setting->odr_bits;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2,
|
||||
ret = i2c_smbus_write_byte_data(data->client, data->regs->wuf_ctrl,
|
||||
odr_setting->wuf_bits);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
|
||||
@ -1094,12 +1212,12 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
|
||||
ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
|
||||
KXCJK1013_REG_XOUT_L,
|
||||
AXIS_MAX * 2,
|
||||
(u8 *)data->buffer);
|
||||
(u8 *)data->scan.chans);
|
||||
mutex_unlock(&data->mutex);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
data->timestamp);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -1113,7 +1231,7 @@ static void kxcjk1013_trig_reen(struct iio_trigger *trig)
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
|
||||
}
|
||||
@ -1166,8 +1284,7 @@ static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
|
||||
int ret = i2c_smbus_read_byte_data(data->client,
|
||||
KXCJK1013_REG_INT_SRC2);
|
||||
int ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src2);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_src2\n");
|
||||
return;
|
||||
@ -1234,7 +1351,7 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_SRC1);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_src1);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "Error reading reg_int_src1\n");
|
||||
goto ack_intr;
|
||||
@ -1257,7 +1374,7 @@ ack_intr:
|
||||
if (data->dready_trigger_on)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
|
||||
ret = i2c_smbus_read_byte_data(data->client, data->regs->int_rel);
|
||||
if (ret < 0)
|
||||
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
|
||||
|
||||
@ -1338,8 +1455,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
||||
} else {
|
||||
data->active_high_intr = true; /* default polarity */
|
||||
|
||||
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
|
||||
&data->orientation);
|
||||
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -1378,6 +1494,22 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
switch (data->chipset) {
|
||||
case KXCJK1013:
|
||||
case KXCJ91008:
|
||||
case KXTJ21009:
|
||||
data->regs = &kxcjk1013_regs;
|
||||
break;
|
||||
case KXTF9:
|
||||
data->regs = &kxtf9_regs;
|
||||
break;
|
||||
case KX0231025:
|
||||
data->regs = &kx0231025_regs;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = kxcjk1013_chip_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1404,7 +1536,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!data->dready_trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_poweroff;
|
||||
@ -1413,7 +1545,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
||||
data->motion_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-any-motion-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!data->motion_trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_poweroff;
|
||||
@ -1485,7 +1617,6 @@ static int kxcjk1013_remove(struct i2c_client *client)
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
if (data->dready_trig) {
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
@ -1593,6 +1724,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
|
||||
{"kxcj91008", KXCJ91008},
|
||||
{"kxtj21009", KXTJ21009},
|
||||
{"kxtf9", KXTF9},
|
||||
{"kx023-1025", KX0231025},
|
||||
{"SMO8500", KXCJ91008},
|
||||
{}
|
||||
};
|
||||
@ -1604,6 +1736,7 @@ static const struct of_device_id kxcjk1013_of_match[] = {
|
||||
{ .compatible = "kionix,kxcj91008", },
|
||||
{ .compatible = "kionix,kxtj21009", },
|
||||
{ .compatible = "kionix,kxtf9", },
|
||||
{ .compatible = "kionix,kx023-1025", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kxcjk1013_of_match);
|
||||
|
@ -420,7 +420,7 @@ int kxsd9_common_probe(struct device *dev,
|
||||
indio_dev->available_scan_masks = kxsd9_scan_masks;
|
||||
|
||||
/* Read the mounting matrix, if present */
|
||||
ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
|
||||
ret = iio_read_mount_matrix(dev, &st->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -221,7 +221,7 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
|
||||
int ret;
|
||||
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
ret = pm_runtime_resume_and_get(&client->dev);
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(&client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&client->dev);
|
||||
@ -230,8 +230,6 @@ static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"failed to change power state to %d\n", on);
|
||||
if (on)
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1461,7 +1459,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
|
||||
|
||||
trig = devm_iio_trigger_alloc(&data->client->dev, "%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!trig)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1711,7 +1709,6 @@ static int mma8452_remove(struct i2c_client *client)
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
mma8452_trigger_cleanup(indio_dev);
|
||||
|
@ -515,7 +515,6 @@ static int mma9551_remove(struct i2c_client *client)
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
mma9551_set_device_state(data->client, false);
|
||||
|
@ -664,7 +664,7 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
|
||||
int ret;
|
||||
|
||||
if (on)
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
ret = pm_runtime_resume_and_get(&client->dev);
|
||||
else {
|
||||
pm_runtime_mark_last_busy(&client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&client->dev);
|
||||
@ -673,8 +673,6 @@ int mma9551_set_power_state(struct i2c_client *client, bool on)
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"failed to change power state to %d\n", on);
|
||||
if (on)
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1154,7 +1154,6 @@ static int mma9553_remove(struct i2c_client *client)
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
mma9551_set_device_state(data->client, false);
|
||||
|
@ -56,7 +56,11 @@ struct mxc4005_data {
|
||||
struct mutex mutex;
|
||||
struct regmap *regmap;
|
||||
struct iio_trigger *dready_trig;
|
||||
__be16 buffer[8];
|
||||
/* Ensure timestamp is naturally aligned */
|
||||
struct {
|
||||
__be16 chans[3];
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
bool trigger_enabled;
|
||||
};
|
||||
|
||||
@ -135,7 +139,7 @@ static int mxc4005_read_xyz(struct mxc4005_data *data)
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
|
||||
data->buffer, sizeof(data->buffer));
|
||||
data->scan.chans, sizeof(data->scan.chans));
|
||||
if (ret < 0) {
|
||||
dev_err(data->dev, "failed to read axes\n");
|
||||
return ret;
|
||||
@ -301,7 +305,7 @@ static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
pf->timestamp);
|
||||
|
||||
err:
|
||||
@ -433,7 +437,7 @@ static int mxc4005_probe(struct i2c_client *client,
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!data->dready_trig)
|
||||
return -ENOMEM;
|
||||
|
||||
|
472
drivers/iio/accel/sca3300.c
Normal file
472
drivers/iio/accel/sca3300.c
Normal file
@ -0,0 +1,472 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Murata SCA3300 3-axis industrial accelerometer
|
||||
*
|
||||
* Copyright (c) 2021 Vaisala Oyj. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/crc8.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define SCA3300_ALIAS "sca3300"
|
||||
|
||||
#define SCA3300_CRC8_POLYNOMIAL 0x1d
|
||||
|
||||
/* Device mode register */
|
||||
#define SCA3300_REG_MODE 0xd
|
||||
#define SCA3300_MODE_SW_RESET 0x20
|
||||
|
||||
/* Last register in map */
|
||||
#define SCA3300_REG_SELBANK 0x1f
|
||||
|
||||
/* Device status and mask */
|
||||
#define SCA3300_REG_STATUS 0x6
|
||||
#define SCA3300_STATUS_MASK GENMASK(8, 0)
|
||||
|
||||
/* Device ID */
|
||||
#define SCA3300_REG_WHOAMI 0x10
|
||||
#define SCA3300_WHOAMI_ID 0x51
|
||||
|
||||
/* Device return status and mask */
|
||||
#define SCA3300_VALUE_RS_ERROR 0x3
|
||||
#define SCA3300_MASK_RS_STATUS GENMASK(1, 0)
|
||||
|
||||
enum sca3300_scan_indexes {
|
||||
SCA3300_ACC_X = 0,
|
||||
SCA3300_ACC_Y,
|
||||
SCA3300_ACC_Z,
|
||||
SCA3300_TEMP,
|
||||
SCA3300_TIMESTAMP,
|
||||
};
|
||||
|
||||
#define SCA3300_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = reg, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_##axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
|
||||
.scan_index = index, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_CPU, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec sca3300_channels[] = {
|
||||
SCA3300_ACCEL_CHANNEL(SCA3300_ACC_X, 0x1, X),
|
||||
SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Y, 0x2, Y),
|
||||
SCA3300_ACCEL_CHANNEL(SCA3300_ACC_Z, 0x3, Z),
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.address = 0x5,
|
||||
.scan_index = SCA3300_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static const int sca3300_lp_freq[] = {70, 70, 70, 10};
|
||||
static const int sca3300_accel_scale[][2] = {{0, 370}, {0, 741}, {0, 185}, {0, 185}};
|
||||
|
||||
static const unsigned long sca3300_scan_masks[] = {
|
||||
BIT(SCA3300_ACC_X) | BIT(SCA3300_ACC_Y) | BIT(SCA3300_ACC_Z) |
|
||||
BIT(SCA3300_TEMP),
|
||||
0
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sca3300_data - device data
|
||||
* @spi: SPI device structure
|
||||
* @lock: Data buffer lock
|
||||
* @scan: Triggered buffer. Four channel 16-bit data + 64-bit timestamp
|
||||
* @txbuf: Transmit buffer
|
||||
* @rxbuf: Receive buffer
|
||||
*/
|
||||
struct sca3300_data {
|
||||
struct spi_device *spi;
|
||||
struct mutex lock;
|
||||
struct {
|
||||
s16 channels[4];
|
||||
s64 ts __aligned(sizeof(s64));
|
||||
} scan;
|
||||
u8 txbuf[4] ____cacheline_aligned;
|
||||
u8 rxbuf[4];
|
||||
};
|
||||
|
||||
DECLARE_CRC8_TABLE(sca3300_crc_table);
|
||||
|
||||
static int sca3300_transfer(struct sca3300_data *sca_data, int *val)
|
||||
{
|
||||
/* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */
|
||||
struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS };
|
||||
int32_t ret;
|
||||
int rs;
|
||||
u8 crc;
|
||||
struct spi_transfer xfers[2] = {
|
||||
{
|
||||
.tx_buf = sca_data->txbuf,
|
||||
.len = ARRAY_SIZE(sca_data->txbuf),
|
||||
.delay = delay,
|
||||
.cs_change = 1,
|
||||
},
|
||||
{
|
||||
.rx_buf = sca_data->rxbuf,
|
||||
.len = ARRAY_SIZE(sca_data->rxbuf),
|
||||
.delay = delay,
|
||||
}
|
||||
};
|
||||
|
||||
/* inverted crc value as described in device data sheet */
|
||||
crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE);
|
||||
sca_data->txbuf[3] = crc;
|
||||
|
||||
ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers));
|
||||
if (ret) {
|
||||
dev_err(&sca_data->spi->dev,
|
||||
"transfer error, error: %d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE);
|
||||
if (sca_data->rxbuf[3] != crc) {
|
||||
dev_err(&sca_data->spi->dev, "CRC checksum mismatch");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* get return status */
|
||||
rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS;
|
||||
if (rs == SCA3300_VALUE_RS_ERROR)
|
||||
ret = -EINVAL;
|
||||
|
||||
*val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sca3300_error_handler(struct sca3300_data *sca_data)
|
||||
{
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
mutex_lock(&sca_data->lock);
|
||||
sca_data->txbuf[0] = SCA3300_REG_STATUS << 2;
|
||||
ret = sca3300_transfer(sca_data, &val);
|
||||
mutex_unlock(&sca_data->lock);
|
||||
/*
|
||||
* Return status error is cleared after reading status register once,
|
||||
* expect EINVAL here.
|
||||
*/
|
||||
if (ret != -EINVAL) {
|
||||
dev_err(&sca_data->spi->dev,
|
||||
"error reading device status: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_err(&sca_data->spi->dev, "device status: 0x%lx\n",
|
||||
val & SCA3300_STATUS_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&sca_data->lock);
|
||||
sca_data->txbuf[0] = reg << 2;
|
||||
ret = sca3300_transfer(sca_data, val);
|
||||
mutex_unlock(&sca_data->lock);
|
||||
if (ret != -EINVAL)
|
||||
return ret;
|
||||
|
||||
return sca3300_error_handler(sca_data);
|
||||
}
|
||||
|
||||
static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val)
|
||||
{
|
||||
int reg_val = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&sca_data->lock);
|
||||
/* BIT(7) for write operation */
|
||||
sca_data->txbuf[0] = BIT(7) | (reg << 2);
|
||||
put_unaligned_be16(val, &sca_data->txbuf[1]);
|
||||
ret = sca3300_transfer(sca_data, ®_val);
|
||||
mutex_unlock(&sca_data->lock);
|
||||
if (ret != -EINVAL)
|
||||
return ret;
|
||||
|
||||
return sca3300_error_handler(sca_data);
|
||||
}
|
||||
|
||||
static int sca3300_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct sca3300_data *data = iio_priv(indio_dev);
|
||||
int reg_val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (val)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sca3300_accel_scale); i++) {
|
||||
if (val2 == sca3300_accel_scale[i][1])
|
||||
return sca3300_write_reg(data, SCA3300_REG_MODE, i);
|
||||
}
|
||||
return -EINVAL;
|
||||
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* freq. change is possible only for mode 3 and 4 */
|
||||
if (reg_val == 2 && val == sca3300_lp_freq[3])
|
||||
return sca3300_write_reg(data, SCA3300_REG_MODE, 3);
|
||||
if (reg_val == 3 && val == sca3300_lp_freq[2])
|
||||
return sca3300_write_reg(data, SCA3300_REG_MODE, 2);
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sca3300_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct sca3300_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
int reg_val;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = sca3300_read_reg(data, chan->address, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = 0;
|
||||
*val2 = sca3300_accel_scale[reg_val][1];
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
ret = sca3300_read_reg(data, SCA3300_REG_MODE, ®_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = sca3300_lp_freq[reg_val];
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t sca3300_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct sca3300_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, val, i = 0;
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
ret = sca3300_read_reg(data, sca3300_channels[bit].address,
|
||||
&val);
|
||||
if (ret) {
|
||||
dev_err_ratelimited(&data->spi->dev,
|
||||
"failed to read register, error: %d\n", ret);
|
||||
/* handled, but bailing out due to errors */
|
||||
goto out;
|
||||
}
|
||||
data->scan.channels[i++] = val;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* sca3300_init - Device init sequence. See datasheet rev 2 section
|
||||
* 4.2 Start-Up Sequence for details.
|
||||
*/
|
||||
static int sca3300_init(struct sca3300_data *sca_data,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
int value = 0;
|
||||
int ret;
|
||||
|
||||
ret = sca3300_write_reg(sca_data, SCA3300_REG_MODE,
|
||||
SCA3300_MODE_SW_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Wait 1ms after SW-reset command.
|
||||
* Wait 15ms for settling of signal paths.
|
||||
*/
|
||||
usleep_range(16e3, 50e3);
|
||||
|
||||
ret = sca3300_read_reg(sca_data, SCA3300_REG_WHOAMI, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (value != SCA3300_WHOAMI_ID) {
|
||||
dev_err(&sca_data->spi->dev,
|
||||
"device id not expected value, %d != %u\n",
|
||||
value, SCA3300_WHOAMI_ID);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sca3300_debugfs_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg, unsigned int writeval,
|
||||
unsigned int *readval)
|
||||
{
|
||||
struct sca3300_data *data = iio_priv(indio_dev);
|
||||
int value;
|
||||
int ret;
|
||||
|
||||
if (reg > SCA3300_REG_SELBANK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!readval)
|
||||
return sca3300_write_reg(data, reg, writeval);
|
||||
|
||||
ret = sca3300_read_reg(data, reg, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*readval = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sca3300_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 = (const int *)sca3300_accel_scale;
|
||||
*length = ARRAY_SIZE(sca3300_accel_scale) * 2 - 2;
|
||||
*type = IIO_VAL_INT_PLUS_MICRO;
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
|
||||
*vals = &sca3300_lp_freq[2];
|
||||
*length = 2;
|
||||
*type = IIO_VAL_INT;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info sca3300_info = {
|
||||
.read_raw = sca3300_read_raw,
|
||||
.write_raw = sca3300_write_raw,
|
||||
.debugfs_reg_access = &sca3300_debugfs_reg_access,
|
||||
.read_avail = sca3300_read_avail,
|
||||
};
|
||||
|
||||
static int sca3300_probe(struct spi_device *spi)
|
||||
{
|
||||
struct sca3300_data *sca_data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*sca_data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
sca_data = iio_priv(indio_dev);
|
||||
mutex_init(&sca_data->lock);
|
||||
sca_data->spi = spi;
|
||||
|
||||
crc8_populate_msb(sca3300_crc_table, SCA3300_CRC8_POLYNOMIAL);
|
||||
|
||||
indio_dev->info = &sca3300_info;
|
||||
indio_dev->name = SCA3300_ALIAS;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = sca3300_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(sca3300_channels);
|
||||
indio_dev->available_scan_masks = sca3300_scan_masks;
|
||||
|
||||
ret = sca3300_init(sca_data, indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to init device, error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
sca3300_trigger_handler, NULL);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"iio triggered buffer setup failed, error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "iio device register failed, error: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id sca3300_dt_ids[] = {
|
||||
{ .compatible = "murata,sca3300"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sca3300_dt_ids);
|
||||
|
||||
static struct spi_driver sca3300_driver = {
|
||||
.driver = {
|
||||
.name = SCA3300_ALIAS,
|
||||
.of_match_table = sca3300_dt_ids,
|
||||
},
|
||||
.probe = sca3300_probe,
|
||||
};
|
||||
module_spi_driver(sca3300_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomas Melin <tomas.melin@vaisala.com>");
|
||||
MODULE_DESCRIPTION("Murata SCA3300 SPI Accelerometer");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -62,18 +62,6 @@ enum st_accel_type {
|
||||
#define LIS2DE12_ACCEL_DEV_NAME "lis2de12"
|
||||
#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12"
|
||||
|
||||
/**
|
||||
* struct st_sensors_platform_data - default accel platform data
|
||||
* @drdy_int_pin: default accel DRDY is available on INT1 pin.
|
||||
*/
|
||||
static __maybe_unused const struct st_sensors_platform_data default_accel_pdata = {
|
||||
.drdy_int_pin = 1,
|
||||
};
|
||||
|
||||
const struct st_sensor_settings *st_accel_get_settings(const char *name);
|
||||
int st_accel_common_probe(struct iio_dev *indio_dev);
|
||||
void st_accel_common_remove(struct iio_dev *indio_dev);
|
||||
|
||||
#ifdef CONFIG_IIO_BUFFER
|
||||
int st_accel_allocate_ring(struct iio_dev *indio_dev);
|
||||
void st_accel_deallocate_ring(struct iio_dev *indio_dev);
|
||||
|
@ -41,51 +41,74 @@
|
||||
#define ST_ACCEL_FS_AVL_200G 200
|
||||
#define ST_ACCEL_FS_AVL_400G 400
|
||||
|
||||
static const struct iio_mount_matrix *
|
||||
st_accel_get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
|
||||
return &adata->mount_matrix;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info st_accel_mount_matrix_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_accel_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_accel_8bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 8, 8,
|
||||
ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 8, 8,
|
||||
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 8, 8,
|
||||
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1),
|
||||
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_accel_12bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 12, 16,
|
||||
ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_ACCEL_DEFAULT_OUT_X_L_ADDR,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 12, 16,
|
||||
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 12, 16,
|
||||
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
|
||||
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3)
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec st_accel_16bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
|
||||
ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_ACCEL_DEFAULT_OUT_X_L_ADDR,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
|
||||
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
ST_SENSORS_LSM_CHANNELS_EXT(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
|
||||
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
|
||||
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR,
|
||||
st_accel_mount_matrix_ext_info),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3)
|
||||
};
|
||||
|
||||
@ -980,7 +1003,99 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
||||
.multi_read_bit = true,
|
||||
.bootime = 2,
|
||||
},
|
||||
{
|
||||
.wai = 0x49,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = LSM9DS0_IMU_DEV_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
|
||||
.odr = {
|
||||
.addr = 0x20,
|
||||
.mask = GENMASK(7, 4),
|
||||
.odr_avl = {
|
||||
{ 3, 0x01, },
|
||||
{ 6, 0x02, },
|
||||
{ 12, 0x03, },
|
||||
{ 25, 0x04, },
|
||||
{ 50, 0x05, },
|
||||
{ 100, 0x06, },
|
||||
{ 200, 0x07, },
|
||||
{ 400, 0x08, },
|
||||
{ 800, 0x09, },
|
||||
{ 1600, 0x0a, },
|
||||
},
|
||||
},
|
||||
.pw = {
|
||||
.addr = 0x20,
|
||||
.mask = GENMASK(7, 4),
|
||||
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
||||
},
|
||||
.enable_axis = {
|
||||
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
|
||||
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
|
||||
},
|
||||
.fs = {
|
||||
.addr = 0x21,
|
||||
.mask = GENMASK(5, 3),
|
||||
.fs_avl = {
|
||||
[0] = {
|
||||
.num = ST_ACCEL_FS_AVL_2G,
|
||||
.value = 0x00,
|
||||
.gain = IIO_G_TO_M_S_2(61),
|
||||
},
|
||||
[1] = {
|
||||
.num = ST_ACCEL_FS_AVL_4G,
|
||||
.value = 0x01,
|
||||
.gain = IIO_G_TO_M_S_2(122),
|
||||
},
|
||||
[2] = {
|
||||
.num = ST_ACCEL_FS_AVL_6G,
|
||||
.value = 0x02,
|
||||
.gain = IIO_G_TO_M_S_2(183),
|
||||
},
|
||||
[3] = {
|
||||
.num = ST_ACCEL_FS_AVL_8G,
|
||||
.value = 0x03,
|
||||
.gain = IIO_G_TO_M_S_2(244),
|
||||
},
|
||||
[4] = {
|
||||
.num = ST_ACCEL_FS_AVL_16G,
|
||||
.value = 0x04,
|
||||
.gain = IIO_G_TO_M_S_2(732),
|
||||
},
|
||||
},
|
||||
},
|
||||
.bdu = {
|
||||
.addr = 0x20,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.drdy_irq = {
|
||||
.int1 = {
|
||||
.addr = 0x22,
|
||||
.mask = BIT(2),
|
||||
},
|
||||
.int2 = {
|
||||
.addr = 0x23,
|
||||
.mask = BIT(3),
|
||||
},
|
||||
.stat_drdy = {
|
||||
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
|
||||
.mask = GENMASK(2, 0),
|
||||
},
|
||||
},
|
||||
.sim = {
|
||||
.addr = 0x21,
|
||||
.value = BIT(0),
|
||||
},
|
||||
.multi_read_bit = true,
|
||||
.bootime = 2,
|
||||
},
|
||||
};
|
||||
|
||||
/* Default accel DRDY is available on INT1 pin */
|
||||
static const struct st_sensors_platform_data default_accel_pdata = {
|
||||
.drdy_int_pin = 1,
|
||||
};
|
||||
|
||||
static int st_accel_read_raw(struct iio_dev *indio_dev,
|
||||
@ -1070,25 +1185,10 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct iio_mount_matrix *
|
||||
get_mount_matrix(const struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
|
||||
return adata->mount_matrix;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info mount_matrix_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, get_mount_matrix),
|
||||
{ },
|
||||
};
|
||||
|
||||
/* Read ST-specific _ONT orientation data from ACPI and generate an
|
||||
* appropriate mount matrix.
|
||||
*/
|
||||
static int apply_acpi_orientation(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *channels)
|
||||
static int apply_acpi_orientation(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
@ -1177,14 +1277,6 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
/* Convert our integer matrix to a string-based iio_mount_matrix */
|
||||
adata->mount_matrix = devm_kmalloc(&indio_dev->dev,
|
||||
sizeof(*adata->mount_matrix),
|
||||
GFP_KERNEL);
|
||||
if (!adata->mount_matrix) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
int matrix_val = final_ont[i][j];
|
||||
@ -1203,26 +1295,25 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
adata->mount_matrix->rotation[i * 3 + j] = str_value;
|
||||
adata->mount_matrix.rotation[i * 3 + j] = str_value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Expose the mount matrix via ext_info */
|
||||
for (i = 0; i < indio_dev->num_channels; i++)
|
||||
channels[i].ext_info = mount_matrix_ext_info;
|
||||
|
||||
ret = 0;
|
||||
dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n");
|
||||
|
||||
out:
|
||||
kfree(buffer.pointer);
|
||||
if (ret)
|
||||
dev_dbg(&indio_dev->dev,
|
||||
"failed to apply ACPI orientation data: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else /* !CONFIG_ACPI */
|
||||
static int apply_acpi_orientation(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec *channels)
|
||||
static int apply_acpi_orientation(struct iio_dev *indio_dev)
|
||||
{
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1248,38 +1339,30 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
struct st_sensors_platform_data *pdata = dev_get_platdata(adata->dev);
|
||||
struct iio_chan_spec *channels;
|
||||
size_t channels_size;
|
||||
int err;
|
||||
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &accel_info;
|
||||
|
||||
err = st_sensors_power_enable(indio_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = st_sensors_verify_id(indio_dev);
|
||||
if (err < 0)
|
||||
goto st_accel_power_off;
|
||||
return err;
|
||||
|
||||
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
|
||||
indio_dev->channels = adata->sensor_settings->ch;
|
||||
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
|
||||
|
||||
channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec);
|
||||
channels = devm_kmemdup(&indio_dev->dev,
|
||||
adata->sensor_settings->ch,
|
||||
channels_size, GFP_KERNEL);
|
||||
if (!channels) {
|
||||
err = -ENOMEM;
|
||||
goto st_accel_power_off;
|
||||
/*
|
||||
* First try specific ACPI methods to retrieve orientation then try the
|
||||
* generic function.
|
||||
*/
|
||||
err = apply_acpi_orientation(indio_dev);
|
||||
if (err) {
|
||||
err = iio_read_mount_matrix(adata->dev, &adata->mount_matrix);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (apply_acpi_orientation(indio_dev, channels))
|
||||
dev_warn(&indio_dev->dev,
|
||||
"failed to apply ACPI orientation data: %d\n", err);
|
||||
|
||||
indio_dev->channels = channels;
|
||||
adata->current_fullscale = &adata->sensor_settings->fs.fs_avl[0];
|
||||
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
|
||||
|
||||
@ -1288,11 +1371,11 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
|
||||
|
||||
err = st_sensors_init_sensor(indio_dev, pdata);
|
||||
if (err < 0)
|
||||
goto st_accel_power_off;
|
||||
return err;
|
||||
|
||||
err = st_accel_allocate_ring(indio_dev);
|
||||
if (err < 0)
|
||||
goto st_accel_power_off;
|
||||
return err;
|
||||
|
||||
if (adata->irq > 0) {
|
||||
err = st_sensors_allocate_trigger(indio_dev,
|
||||
@ -1315,9 +1398,6 @@ st_accel_device_register_error:
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
st_accel_probe_trigger_error:
|
||||
st_accel_deallocate_ring(indio_dev);
|
||||
st_accel_power_off:
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(st_accel_common_probe);
|
||||
@ -1326,8 +1406,6 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct st_sensor_data *adata = iio_priv(indio_dev);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (adata->irq > 0)
|
||||
st_sensors_deallocate_trigger(indio_dev);
|
||||
|
@ -174,16 +174,29 @@ static int st_accel_i2c_probe(struct i2c_client *client)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = st_accel_common_probe(indio_dev);
|
||||
if (ret < 0)
|
||||
ret = st_sensors_power_enable(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = st_accel_common_probe(indio_dev);
|
||||
if (ret < 0)
|
||||
goto st_accel_power_off;
|
||||
|
||||
return 0;
|
||||
|
||||
st_accel_power_off:
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int st_accel_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
st_accel_common_remove(i2c_get_clientdata(client));
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
st_accel_common_remove(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -123,16 +123,29 @@ static int st_accel_spi_probe(struct spi_device *spi)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = st_accel_common_probe(indio_dev);
|
||||
if (err < 0)
|
||||
err = st_sensors_power_enable(indio_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = st_accel_common_probe(indio_dev);
|
||||
if (err < 0)
|
||||
goto st_accel_power_off;
|
||||
|
||||
return 0;
|
||||
|
||||
st_accel_power_off:
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int st_accel_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
st_accel_common_remove(spi_get_drvdata(spi));
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
|
||||
st_sensors_power_disable(indio_dev);
|
||||
|
||||
st_accel_common_remove(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
* IIO driver for STK8312; 7-bit I2C address: 0x3D.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -103,7 +102,11 @@ struct stk8312_data {
|
||||
u8 mode;
|
||||
struct iio_trigger *dready_trig;
|
||||
bool dready_trigger_on;
|
||||
s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */
|
||||
/* Ensure timestamp is naturally aligned */
|
||||
struct {
|
||||
s8 chans[3];
|
||||
s64 timestamp __aligned(8);
|
||||
} scan;
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
|
||||
@ -438,7 +441,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client,
|
||||
STK8312_REG_XOUT,
|
||||
STK8312_ALL_CHANNEL_SIZE,
|
||||
data->buffer);
|
||||
data->scan.chans);
|
||||
if (ret < STK8312_ALL_CHANNEL_SIZE) {
|
||||
dev_err(&data->client->dev, "register read failed\n");
|
||||
mutex_unlock(&data->lock);
|
||||
@ -452,12 +455,12 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
|
||||
mutex_unlock(&data->lock);
|
||||
goto err;
|
||||
}
|
||||
data->buffer[i++] = ret;
|
||||
data->scan.chans[i++] = ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
pf->timestamp);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
@ -552,7 +555,7 @@ static int stk8312_probe(struct i2c_client *client,
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!data->dready_trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_power_off;
|
||||
@ -635,23 +638,17 @@ static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id stk8312_i2c_id[] = {
|
||||
{"STK8312", 0},
|
||||
/* Deprecated in favour of lowercase form */
|
||||
{ "STK8312", 0 },
|
||||
{ "stk8312", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
|
||||
|
||||
static const struct acpi_device_id stk8312_acpi_id[] = {
|
||||
{"STK8312", 0},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
|
||||
|
||||
static struct i2c_driver stk8312_driver = {
|
||||
.driver = {
|
||||
.name = STK8312_DRIVER_NAME,
|
||||
.pm = STK8312_PM_OPS,
|
||||
.acpi_match_table = ACPI_PTR(stk8312_acpi_id),
|
||||
},
|
||||
.probe = stk8312_probe,
|
||||
.remove = stk8312_remove,
|
||||
|
@ -91,12 +91,11 @@ struct stk8ba50_data {
|
||||
u8 sample_rate_idx;
|
||||
struct iio_trigger *dready_trig;
|
||||
bool dready_trigger_on;
|
||||
/*
|
||||
* 3 x 16-bit channels (10-bit data, 6-bit padding) +
|
||||
* 1 x 16 padding +
|
||||
* 4 x 16 64-bit timestamp
|
||||
*/
|
||||
s16 buffer[8];
|
||||
/* Ensure timestamp is naturally aligned */
|
||||
struct {
|
||||
s16 chans[3];
|
||||
s64 timetamp __aligned(8);
|
||||
} scan;
|
||||
};
|
||||
|
||||
#define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \
|
||||
@ -324,7 +323,7 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client,
|
||||
STK8BA50_REG_XOUT,
|
||||
STK8BA50_ALL_CHANNEL_SIZE,
|
||||
(u8 *)data->buffer);
|
||||
(u8 *)data->scan.chans);
|
||||
if (ret < STK8BA50_ALL_CHANNEL_SIZE) {
|
||||
dev_err(&data->client->dev, "register read failed\n");
|
||||
goto err;
|
||||
@ -337,10 +336,10 @@ static irqreturn_t stk8ba50_trigger_handler(int irq, void *p)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
data->buffer[i++] = ret;
|
||||
data->scan.chans[i++] = ret;
|
||||
}
|
||||
}
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
pf->timestamp);
|
||||
err:
|
||||
mutex_unlock(&data->lock);
|
||||
@ -448,7 +447,7 @@ static int stk8ba50_probe(struct i2c_client *client,
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
indio_dev->name,
|
||||
indio_dev->id);
|
||||
iio_device_id(indio_dev));
|
||||
if (!data->dready_trig) {
|
||||
ret = -ENOMEM;
|
||||
goto err_power_off;
|
||||
|
@ -1190,6 +1190,18 @@ config TI_TLC4541
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called ti-tlc4541.
|
||||
|
||||
config TI_TSC2046
|
||||
tristate "Texas Instruments TSC2046 ADC driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for ADC functionality of Texas
|
||||
Instruments TSC2046 touch screen controller.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called ti-tsc2046.
|
||||
|
||||
config TWL4030_MADC
|
||||
tristate "TWL4030 MADC (Monitoring A/D Converter)"
|
||||
depends on TWL4030_CORE
|
||||
|
@ -106,6 +106,7 @@ obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
|
||||
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
|
||||
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
|
||||
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
|
||||
obj-$(CONFIG_TI_TSC2046) += ti-tsc2046.o
|
||||
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
|
||||
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
|
||||
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
|
||||
|
@ -862,6 +862,11 @@ static void ad7124_reg_disable(void *r)
|
||||
regulator_disable(r);
|
||||
}
|
||||
|
||||
static void ad7124_clk_disable(void *c)
|
||||
{
|
||||
clk_disable_unprepare(c);
|
||||
}
|
||||
|
||||
static int ad7124_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7124_chip_info *info;
|
||||
@ -883,8 +888,6 @@ static int ad7124_probe(struct spi_device *spi)
|
||||
|
||||
ad_sd_init(&st->sd, indio_dev, spi, &ad7124_sigma_delta_info);
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = st->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &ad7124_info;
|
||||
@ -922,48 +925,28 @@ static int ad7124_probe(struct spi_device *spi)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7124_clk_disable, st->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad7124_soft_reset(st);
|
||||
if (ret < 0)
|
||||
goto error_clk_disable_unprepare;
|
||||
return ret;
|
||||
|
||||
ret = ad7124_check_chip_id(st);
|
||||
if (ret)
|
||||
goto error_clk_disable_unprepare;
|
||||
return ret;
|
||||
|
||||
ret = ad7124_setup(st);
|
||||
if (ret < 0)
|
||||
goto error_clk_disable_unprepare;
|
||||
return ret;
|
||||
|
||||
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_clk_disable_unprepare;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to register iio device\n");
|
||||
goto error_remove_trigger;
|
||||
}
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove_trigger:
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
error_clk_disable_unprepare:
|
||||
clk_disable_unprepare(st->mclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7124_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad7124_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
clk_disable_unprepare(st->mclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7124_of_match[] = {
|
||||
@ -981,7 +964,6 @@ static struct spi_driver ad71124_driver = {
|
||||
.of_match_table = ad7124_of_match,
|
||||
},
|
||||
.probe = ad7124_probe,
|
||||
.remove = ad7124_remove,
|
||||
};
|
||||
module_spi_driver(ad71124_driver);
|
||||
|
||||
|
@ -326,7 +326,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
|
||||
clock_sel = AD7192_CLK_INT;
|
||||
|
||||
/* use internal clock */
|
||||
if (PTR_ERR(st->mclk) == -ENOENT) {
|
||||
if (st->mclk) {
|
||||
if (of_property_read_bool(np, "adi,int-clock-output-enable"))
|
||||
clock_sel = AD7192_CLK_INT_CO;
|
||||
} else {
|
||||
@ -908,6 +908,16 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad7192_reg_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static void ad7192_clk_disable(void *clk)
|
||||
{
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
static int ad7192_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7192_state *st;
|
||||
@ -937,33 +947,38 @@ static int ad7192_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->avdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->dvdd = devm_regulator_get(&spi->dev, "dvdd");
|
||||
if (IS_ERR(st->dvdd)) {
|
||||
ret = PTR_ERR(st->dvdd);
|
||||
goto error_disable_avdd;
|
||||
}
|
||||
if (IS_ERR(st->dvdd))
|
||||
return PTR_ERR(st->dvdd);
|
||||
|
||||
ret = regulator_enable(st->dvdd);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable specified DVdd supply\n");
|
||||
goto error_disable_avdd;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, st->dvdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_get_voltage(st->avdd);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
|
||||
goto error_disable_avdd;
|
||||
return ret;
|
||||
}
|
||||
st->int_vref_mv = ret / 1000;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->chip_info = of_device_get_match_data(&spi->dev);
|
||||
indio_dev->name = st->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = ad7192_channels_config(indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_disable_dvdd;
|
||||
return ret;
|
||||
|
||||
if (st->chip_info->chip_id == CHIPID_AD7195)
|
||||
indio_dev->info = &ad7195_info;
|
||||
@ -972,17 +987,15 @@ static int ad7192_probe(struct spi_device *spi)
|
||||
|
||||
ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
|
||||
|
||||
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
goto error_disable_dvdd;
|
||||
return ret;
|
||||
|
||||
st->fclk = AD7192_INT_FREQ_MHZ;
|
||||
|
||||
st->mclk = devm_clk_get(&st->sd.spi->dev, "mclk");
|
||||
if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) {
|
||||
ret = PTR_ERR(st->mclk);
|
||||
goto error_remove_trigger;
|
||||
}
|
||||
st->mclk = devm_clk_get_optional(&spi->dev, "mclk");
|
||||
if (IS_ERR(st->mclk))
|
||||
return PTR_ERR(st->mclk);
|
||||
|
||||
st->clock_sel = ad7192_of_clock_select(st);
|
||||
|
||||
@ -990,55 +1003,26 @@ static int ad7192_probe(struct spi_device *spi)
|
||||
st->clock_sel == AD7192_CLK_EXT_MCLK2) {
|
||||
ret = clk_prepare_enable(st->mclk);
|
||||
if (ret < 0)
|
||||
goto error_remove_trigger;
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7192_clk_disable,
|
||||
st->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->fclk = clk_get_rate(st->mclk);
|
||||
if (!ad7192_valid_external_frequency(st->fclk)) {
|
||||
ret = -EINVAL;
|
||||
dev_err(&spi->dev,
|
||||
"External clock frequency out of bounds\n");
|
||||
goto error_disable_clk;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ad7192_setup(st, spi->dev.of_node);
|
||||
if (ret)
|
||||
goto error_disable_clk;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_disable_clk;
|
||||
return 0;
|
||||
|
||||
error_disable_clk:
|
||||
if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
|
||||
st->clock_sel == AD7192_CLK_EXT_MCLK2)
|
||||
clk_disable_unprepare(st->mclk);
|
||||
error_remove_trigger:
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
error_disable_dvdd:
|
||||
regulator_disable(st->dvdd);
|
||||
error_disable_avdd:
|
||||
regulator_disable(st->avdd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7192_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad7192_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
|
||||
st->clock_sel == AD7192_CLK_EXT_MCLK2)
|
||||
clk_disable_unprepare(st->mclk);
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
|
||||
regulator_disable(st->dvdd);
|
||||
regulator_disable(st->avdd);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ad7192_of_match[] = {
|
||||
@ -1056,7 +1040,6 @@ static struct spi_driver ad7192_driver = {
|
||||
.of_match_table = ad7192_of_match,
|
||||
},
|
||||
.probe = ad7192_probe,
|
||||
.remove = ad7192_remove,
|
||||
};
|
||||
module_spi_driver(ad7192_driver);
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
@ -346,6 +347,12 @@ static int ad7298_probe(struct spi_device *spi)
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id ad7298_acpi_ids[] = {
|
||||
{ "INT3494", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ad7298_acpi_ids);
|
||||
|
||||
static const struct spi_device_id ad7298_id[] = {
|
||||
{"ad7298", 0},
|
||||
{}
|
||||
@ -355,6 +362,7 @@ MODULE_DEVICE_TABLE(spi, ad7298_id);
|
||||
static struct spi_driver ad7298_driver = {
|
||||
.driver = {
|
||||
.name = "ad7298",
|
||||
.acpi_match_table = ad7298_acpi_ids,
|
||||
},
|
||||
.probe = ad7298_probe,
|
||||
.id_table = ad7298_id,
|
||||
|
@ -32,12 +32,14 @@ struct ad7476_chip_info {
|
||||
/* channels used when convst gpio is defined */
|
||||
struct iio_chan_spec convst_channel[2];
|
||||
void (*reset)(struct ad7476_state *);
|
||||
bool has_vref;
|
||||
bool has_vdrive;
|
||||
};
|
||||
|
||||
struct ad7476_state {
|
||||
struct spi_device *spi;
|
||||
const struct ad7476_chip_info *chip_info;
|
||||
struct regulator *reg;
|
||||
struct regulator *ref_reg;
|
||||
struct gpio_desc *convst_gpio;
|
||||
struct spi_transfer xfer;
|
||||
struct spi_message msg;
|
||||
@ -52,13 +54,17 @@ struct ad7476_state {
|
||||
};
|
||||
|
||||
enum ad7476_supported_device_ids {
|
||||
ID_AD7091,
|
||||
ID_AD7091R,
|
||||
ID_AD7273,
|
||||
ID_AD7274,
|
||||
ID_AD7276,
|
||||
ID_AD7277,
|
||||
ID_AD7278,
|
||||
ID_AD7466,
|
||||
ID_AD7467,
|
||||
ID_AD7468,
|
||||
ID_AD7475,
|
||||
ID_AD7495,
|
||||
ID_AD7940,
|
||||
ID_ADC081S,
|
||||
@ -145,8 +151,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
|
||||
GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (!st->chip_info->int_vref_uv) {
|
||||
scale_uv = regulator_get_voltage(st->reg);
|
||||
if (st->ref_reg) {
|
||||
scale_uv = regulator_get_voltage(st->ref_reg);
|
||||
if (scale_uv < 0)
|
||||
return scale_uv;
|
||||
} else {
|
||||
@ -187,13 +193,32 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
|
||||
BIT(IIO_CHAN_INFO_RAW))
|
||||
|
||||
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
|
||||
[ID_AD7091R] = {
|
||||
[ID_AD7091] = {
|
||||
.channel[0] = AD7091R_CHAN(12),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.convst_channel[0] = AD7091R_CONVST_CHAN(12),
|
||||
.convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.reset = ad7091_reset,
|
||||
},
|
||||
[ID_AD7091R] = {
|
||||
.channel[0] = AD7091R_CHAN(12),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.convst_channel[0] = AD7091R_CONVST_CHAN(12),
|
||||
.convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.int_vref_uv = 2500000,
|
||||
.has_vref = true,
|
||||
.reset = ad7091_reset,
|
||||
},
|
||||
[ID_AD7273] = {
|
||||
.channel[0] = AD7940_CHAN(10),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.has_vref = true,
|
||||
},
|
||||
[ID_AD7274] = {
|
||||
.channel[0] = AD7940_CHAN(12),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.has_vref = true,
|
||||
},
|
||||
[ID_AD7276] = {
|
||||
.channel[0] = AD7940_CHAN(12),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
@ -218,10 +243,17 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
|
||||
.channel[0] = AD7476_CHAN(8),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
},
|
||||
[ID_AD7475] = {
|
||||
.channel[0] = AD7476_CHAN(12),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.has_vref = true,
|
||||
.has_vdrive = true,
|
||||
},
|
||||
[ID_AD7495] = {
|
||||
.channel[0] = AD7476_CHAN(12),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.int_vref_uv = 2500000,
|
||||
.has_vdrive = true,
|
||||
},
|
||||
[ID_AD7940] = {
|
||||
.channel[0] = AD7940_CHAN(14),
|
||||
@ -254,6 +286,7 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
|
||||
[ID_LTC2314_14] = {
|
||||
.channel[0] = AD7940_CHAN(14),
|
||||
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
.has_vref = true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -263,15 +296,16 @@ static const struct iio_info ad7476_info = {
|
||||
|
||||
static void ad7476_reg_disable(void *data)
|
||||
{
|
||||
struct ad7476_state *st = data;
|
||||
struct regulator *reg = data;
|
||||
|
||||
regulator_disable(st->reg);
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int ad7476_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7476_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct regulator *reg;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
@ -282,27 +316,79 @@ static int ad7476_probe(struct spi_device *spi)
|
||||
st->chip_info =
|
||||
&ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
st->reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
if (IS_ERR(st->reg))
|
||||
return PTR_ERR(st->reg);
|
||||
reg = devm_regulator_get(&spi->dev, "vcc");
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
ret = regulator_enable(st->reg);
|
||||
ret = regulator_enable(reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
|
||||
st);
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Either vcc or vref (below) as appropriate */
|
||||
if (!st->chip_info->int_vref_uv)
|
||||
st->ref_reg = reg;
|
||||
|
||||
if (st->chip_info->has_vref) {
|
||||
|
||||
/* If a device has an internal reference vref is optional */
|
||||
if (st->chip_info->int_vref_uv) {
|
||||
reg = devm_regulator_get_optional(&spi->dev, "vref");
|
||||
if (IS_ERR(reg) && (PTR_ERR(reg) != -ENODEV))
|
||||
return PTR_ERR(reg);
|
||||
} else {
|
||||
reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
}
|
||||
|
||||
if (!IS_ERR(reg)) {
|
||||
ret = regulator_enable(reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev,
|
||||
ad7476_reg_disable,
|
||||
reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
st->ref_reg = reg;
|
||||
} else {
|
||||
/*
|
||||
* Can only get here if device supports both internal
|
||||
* and external reference, but the regulator connected
|
||||
* to the external reference is not connected.
|
||||
* Set the reference regulator pointer to NULL to
|
||||
* indicate this.
|
||||
*/
|
||||
st->ref_reg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (st->chip_info->has_vdrive) {
|
||||
reg = devm_regulator_get(&spi->dev, "vdrive");
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
|
||||
ret = regulator_enable(reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable,
|
||||
reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->convst_gpio = devm_gpiod_get_optional(&spi->dev,
|
||||
"adi,conversion-start",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->convst_gpio))
|
||||
return PTR_ERR(st->convst_gpio);
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
st->spi = spi;
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
@ -333,17 +419,17 @@ static int ad7476_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7476_id[] = {
|
||||
{"ad7091", ID_AD7091R},
|
||||
{"ad7091", ID_AD7091},
|
||||
{"ad7091r", ID_AD7091R},
|
||||
{"ad7273", ID_AD7277},
|
||||
{"ad7274", ID_AD7276},
|
||||
{"ad7273", ID_AD7273},
|
||||
{"ad7274", ID_AD7274},
|
||||
{"ad7276", ID_AD7276},
|
||||
{"ad7277", ID_AD7277},
|
||||
{"ad7278", ID_AD7278},
|
||||
{"ad7466", ID_AD7466},
|
||||
{"ad7467", ID_AD7467},
|
||||
{"ad7468", ID_AD7468},
|
||||
{"ad7475", ID_AD7466},
|
||||
{"ad7475", ID_AD7475},
|
||||
{"ad7476", ID_AD7466},
|
||||
{"ad7476a", ID_AD7466},
|
||||
{"ad7477", ID_AD7467},
|
||||
|
@ -663,7 +663,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
}
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!st->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -248,7 +248,8 @@ static int ad7766_probe(struct spi_device *spi)
|
||||
|
||||
if (spi->irq > 0) {
|
||||
ad7766->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!ad7766->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -272,8 +273,6 @@ static int ad7766_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
ad7766->spi = spi;
|
||||
|
||||
/* First byte always 0 */
|
||||
@ -289,10 +288,7 @@ static int ad7766_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7766_id[] = {
|
||||
|
@ -614,7 +614,6 @@ static int ad7768_probe(struct spi_device *spi)
|
||||
|
||||
st->mclk_freq = clk_get_rate(st->mclk);
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
mutex_init(&st->lock);
|
||||
|
||||
indio_dev->channels = ad7768_channels;
|
||||
@ -630,7 +629,8 @@ static int ad7768_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!st->trig)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -300,6 +300,11 @@ static int ad7780_init_gpios(struct device *dev, struct ad7780_state *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad7780_reg_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int ad7780_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7780_state *st;
|
||||
@ -318,8 +323,6 @@ static int ad7780_probe(struct spi_device *spi)
|
||||
st->chip_info =
|
||||
&ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = &st->chip_info->channel;
|
||||
@ -340,35 +343,15 @@ static int ad7780_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7780_reg_disable, st->reg);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
goto error_cleanup_buffer_and_trigger;
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
error_cleanup_buffer_and_trigger:
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
error_disable_reg:
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7780_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad7780_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7780_id[] = {
|
||||
@ -385,7 +368,6 @@ static struct spi_driver ad7780_driver = {
|
||||
.name = "ad7780",
|
||||
},
|
||||
.probe = ad7780_probe,
|
||||
.remove = ad7780_remove,
|
||||
.id_table = ad7780_id,
|
||||
};
|
||||
module_spi_driver(ad7780_driver);
|
||||
|
@ -394,6 +394,11 @@ static int ad7791_setup(struct ad7791_state *st,
|
||||
st->mode);
|
||||
}
|
||||
|
||||
static void ad7791_reg_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int ad7791_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad7791_platform_data *pdata = spi->dev.platform_data;
|
||||
@ -420,11 +425,13 @@ static int ad7791_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7791_reg_disable, st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data];
|
||||
ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info);
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->info->channels;
|
||||
@ -434,39 +441,15 @@ static int ad7791_probe(struct spi_device *spi)
|
||||
else
|
||||
indio_dev->info = &ad7791_no_filter_info;
|
||||
|
||||
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
return ret;
|
||||
|
||||
ret = ad7791_setup(st, pdata);
|
||||
if (ret)
|
||||
goto error_remove_trigger;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_remove_trigger;
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove_trigger:
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
error_disable_reg:
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7791_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad7791_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7791_spi_ids[] = {
|
||||
@ -484,7 +467,6 @@ static struct spi_driver ad7791_driver = {
|
||||
.name = "ad7791",
|
||||
},
|
||||
.probe = ad7791_probe,
|
||||
.remove = ad7791_remove,
|
||||
.id_table = ad7791_spi_ids,
|
||||
};
|
||||
module_spi_driver(ad7791_driver);
|
||||
|
@ -769,6 +769,11 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static void ad7793_reg_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int ad7793_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
|
||||
@ -803,11 +808,13 @@ static int ad7793_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7793_reg_disable, st->reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vref_mv = regulator_get_voltage(st->reg);
|
||||
if (vref_mv < 0) {
|
||||
ret = vref_mv;
|
||||
goto error_disable_reg;
|
||||
}
|
||||
if (vref_mv < 0)
|
||||
return vref_mv;
|
||||
|
||||
vref_mv /= 1000;
|
||||
} else {
|
||||
@ -817,50 +824,21 @@ static int ad7793_probe(struct spi_device *spi)
|
||||
st->chip_info =
|
||||
&ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = st->chip_info->channels;
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
indio_dev->info = st->chip_info->iio_info;
|
||||
|
||||
ret = ad_sd_setup_buffer_and_trigger(indio_dev);
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
goto error_disable_reg;
|
||||
return ret;
|
||||
|
||||
ret = ad7793_setup(indio_dev, pdata, vref_mv);
|
||||
if (ret)
|
||||
goto error_remove_trigger;
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_remove_trigger;
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove_trigger:
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
error_disable_reg:
|
||||
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7793_remove(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7793_platform_data *pdata = spi->dev.platform_data;
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad7793_state *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
ad_sd_cleanup_buffer_and_trigger(indio_dev);
|
||||
|
||||
if (pdata->refsel != AD7793_REFSEL_INTERNAL)
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad7793_id[] = {
|
||||
@ -882,7 +860,6 @@ static struct spi_driver ad7793_driver = {
|
||||
.name = "ad7793",
|
||||
},
|
||||
.probe = ad7793_probe,
|
||||
.remove = ad7793_remove,
|
||||
.id_table = ad7793_id,
|
||||
};
|
||||
module_spi_driver(ad7793_driver);
|
||||
|
@ -268,7 +268,6 @@ static int ad7887_probe(struct spi_device *spi)
|
||||
st->chip_info =
|
||||
&ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->spi = spi;
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
|
@ -434,8 +434,6 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, st);
|
||||
|
||||
conv->chip_info = &info->axi_adc_info;
|
||||
|
||||
id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
|
||||
|
@ -470,91 +470,65 @@ EXPORT_SYMBOL_GPL(ad_sd_validate_trigger);
|
||||
static const struct iio_trigger_ops ad_sd_trigger_ops = {
|
||||
};
|
||||
|
||||
static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
|
||||
static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
|
||||
int ret;
|
||||
|
||||
sigma_delta->trig = iio_trigger_alloc(&sigma_delta->spi->dev,
|
||||
"%s-dev%d", indio_dev->name,
|
||||
indio_dev->id);
|
||||
if (sigma_delta->trig == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_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;
|
||||
|
||||
sigma_delta->trig->ops = &ad_sd_trigger_ops;
|
||||
init_completion(&sigma_delta->completion);
|
||||
|
||||
sigma_delta->irq_dis = true;
|
||||
ret = request_irq(sigma_delta->spi->irq,
|
||||
ad_sd_data_rdy_trig_poll,
|
||||
sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
|
||||
indio_dev->name,
|
||||
sigma_delta);
|
||||
ret = devm_request_irq(dev, sigma_delta->spi->irq,
|
||||
ad_sd_data_rdy_trig_poll,
|
||||
sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
|
||||
indio_dev->name,
|
||||
sigma_delta);
|
||||
if (ret)
|
||||
goto error_free_trig;
|
||||
return ret;
|
||||
|
||||
iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
|
||||
|
||||
ret = iio_trigger_register(sigma_delta->trig);
|
||||
ret = devm_iio_trigger_register(dev, sigma_delta->trig);
|
||||
if (ret)
|
||||
goto error_free_irq;
|
||||
return ret;
|
||||
|
||||
/* select default trigger */
|
||||
indio_dev->trig = iio_trigger_get(sigma_delta->trig);
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_irq:
|
||||
free_irq(sigma_delta->spi->irq, sigma_delta);
|
||||
error_free_trig:
|
||||
iio_trigger_free(sigma_delta->trig);
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ad_sd_remove_trigger(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
|
||||
|
||||
iio_trigger_unregister(sigma_delta->trig);
|
||||
free_irq(sigma_delta->spi->irq, sigma_delta);
|
||||
iio_trigger_free(sigma_delta->trig);
|
||||
}
|
||||
|
||||
/**
|
||||
* ad_sd_setup_buffer_and_trigger() -
|
||||
* devm_ad_sd_setup_buffer_and_trigger() - Device-managed buffer & trigger setup
|
||||
* @dev: Device object to which to bind the life-time of the resources attached
|
||||
* @indio_dev: The IIO device
|
||||
*/
|
||||
int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev)
|
||||
int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
|
||||
&ad_sd_trigger_handler, &ad_sd_buffer_setup_ops);
|
||||
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;
|
||||
|
||||
ret = ad_sd_probe_trigger(indio_dev);
|
||||
if (ret) {
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return devm_ad_sd_probe_trigger(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger);
|
||||
|
||||
/**
|
||||
* ad_sd_cleanup_buffer_and_trigger() -
|
||||
* @indio_dev: The IIO device
|
||||
*/
|
||||
void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev)
|
||||
{
|
||||
ad_sd_remove_trigger(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger);
|
||||
EXPORT_SYMBOL_GPL(devm_ad_sd_setup_buffer_and_trigger);
|
||||
|
||||
/**
|
||||
* ad_sd_init() - Initializes a ad_sigma_delta struct
|
||||
|
@ -202,29 +202,25 @@ static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv)
|
||||
kfree(cl);
|
||||
}
|
||||
|
||||
static void devm_adi_axi_adc_conv_release(struct device *dev, void *res)
|
||||
static void devm_adi_axi_adc_conv_release(void *conv)
|
||||
{
|
||||
adi_axi_adc_conv_unregister(*(struct adi_axi_adc_conv **)res);
|
||||
adi_axi_adc_conv_unregister(conv);
|
||||
}
|
||||
|
||||
struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
|
||||
size_t sizeof_priv)
|
||||
{
|
||||
struct adi_axi_adc_conv **ptr, *conv;
|
||||
|
||||
ptr = devres_alloc(devm_adi_axi_adc_conv_release, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
struct adi_axi_adc_conv *conv;
|
||||
int ret;
|
||||
|
||||
conv = adi_axi_adc_conv_register(dev, sizeof_priv);
|
||||
if (IS_ERR(conv)) {
|
||||
devres_free(ptr);
|
||||
return ERR_CAST(conv);
|
||||
}
|
||||
if (IS_ERR(conv))
|
||||
return conv;
|
||||
|
||||
*ptr = conv;
|
||||
devres_add(dev, ptr);
|
||||
ret = devm_add_action_or_reset(dev, devm_adi_axi_adc_conv_release,
|
||||
conv);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return conv;
|
||||
}
|
||||
|
@ -403,7 +403,8 @@ struct at91_adc_state {
|
||||
struct at91_adc_dma dma_st;
|
||||
struct at91_adc_touch touch_st;
|
||||
struct iio_dev *indio_dev;
|
||||
u16 buffer[AT91_BUFFER_MAX_HWORDS];
|
||||
/* Ensure naturally aligned timestamp */
|
||||
u16 buffer[AT91_BUFFER_MAX_HWORDS] __aligned(8);
|
||||
/*
|
||||
* lock to prevent concurrent 'single conversion' requests through
|
||||
* sysfs.
|
||||
@ -997,7 +998,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio,
|
||||
int ret;
|
||||
|
||||
trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name,
|
||||
indio->id, trigger_name);
|
||||
iio_device_id(indio), trigger_name);
|
||||
if (!trig)
|
||||
return NULL;
|
||||
|
||||
|
@ -547,7 +547,7 @@ static int at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
|
||||
char *name = kasprintf(GFP_KERNEL,
|
||||
"%s-dev%d-%s",
|
||||
idev->name,
|
||||
idev->id,
|
||||
iio_device_id(idev),
|
||||
triggers[i].name);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
@ -626,7 +626,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
|
||||
int ret;
|
||||
|
||||
trig = iio_trigger_alloc(idev->dev.parent, "%s-dev%d-%s", idev->name,
|
||||
idev->id, trigger->name);
|
||||
iio_device_id(idev), trigger->name);
|
||||
if (trig == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -649,7 +649,8 @@ static int dln2_adc_probe(struct platform_device *pdev)
|
||||
indio_dev->setup_ops = &dln2_adc_buffer_setup_ops;
|
||||
|
||||
dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
|
||||
indio_dev->name, indio_dev->id);
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!dln2->trig) {
|
||||
dev_err(dev, "failed to allocate trigger\n");
|
||||
return -ENOMEM;
|
||||
|
@ -165,10 +165,8 @@ static int ep93xx_adc_probe(struct platform_device *pdev)
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->base)) {
|
||||
dev_err(&pdev->dev, "Cannot map memory resource\n");
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
}
|
||||
|
||||
iiodev->name = dev_name(&pdev->dev);
|
||||
iiodev->modes = INDIO_DIRECT_MODE;
|
||||
|
@ -794,7 +794,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
|
||||
struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct iio_dev *indio_dev = NULL;
|
||||
bool has_ts = false;
|
||||
int ret = -ENODEV;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user