1
0
Fork 0

Staging/IIO patches for 5.6-rc1

Here is the big staging/iio driver patches for 5.6-rc1
 
 Included in here are:
 	- lots of new IIO drivers and updates for that subsystem
 	- the usual huge quantity of minor cleanups for staging drivers
 	- removal of the following staging drivers:
 		- isdn/avm
 		- isdn/gigaset
 		- isdn/hysdn
 		- octeon-usb
 		- octeon ethernet
 
 Overall we deleted far more lines than we added, removing over 40k of
 old and obsolete driver code.
 
 All of these changes have been in linux-next for a while with no
 reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXjFOKw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yly3wCfac6fbfrpwZ2VeUFyT5EJFr9JnKEAn1VMQTIJ
 QCgCqbQemnXfbOXiA5pZ
 =rP6a
 -----END PGP SIGNATURE-----

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

Pull staging and IIO updates from Greg KH:
 "Here is the big staging/iio driver patches for 5.6-rc1

  Included in here are:

   - lots of new IIO drivers and updates for that subsystem

   - the usual huge quantity of minor cleanups for staging drivers

   - removal of the following staging drivers:
       - isdn/avm
       - isdn/gigaset
       - isdn/hysdn
       - octeon-usb
       - octeon ethernet

  Overall we deleted far more lines than we added, removing over 40k of
  old and obsolete driver code.

  All of these changes have been in linux-next for a while with no
  reported issues"

* tag 'staging-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (353 commits)
  staging: most: usb: check for NULL device
  staging: next: configfs: fix release link
  staging: most: core: fix logging messages
  staging: most: core: remove container struct
  staging: most: remove struct device core driver
  staging: most: core: drop device reference
  staging: most: remove device from interface structure
  staging: comedi: drivers: fix spelling mistake "to" -> "too"
  staging: exfat: remove fs_func struct.
  staging: wilc1000: avoid mutex unlock without lock in wilc_wlan_handle_txq()
  staging: wilc1000: return zero on success and non-zero on function failure
  staging: axis-fifo: replace spinlock with mutex
  staging: wilc1000: remove unused code prior to throughput enhancement in SPI
  staging: wilc1000: added 'wilc_' prefix for 'struct assoc_resp' name
  staging: wilc1000: move firmware API struct's to separate header file
  staging: wilc1000: remove use of infinite loop conditions
  staging: kpc2000: rename variables with kpc namespace
  staging: vt6656: Remove memory buffer from vnt_download_firmware.
  staging: vt6656: Just check NEWRSR_DECRYPTOK for RX_FLAG_DECRYPTED.
  staging: vt6656: Use vnt_rx_tail struct for tail variables.
  ...
alistair/sensors
Linus Torvalds 2020-01-29 10:15:11 -08:00
commit 7ba31c3f2f
351 changed files with 7843 additions and 41008 deletions

View File

@ -1726,3 +1726,16 @@ Contact: linux-iio@vger.kernel.org
Description:
List of valid periods (in seconds) for which the light intensity
must be above the threshold level before interrupt is asserted.
What: /sys/bus/iio/devices/iio:deviceX/in_filter_notch_center_frequency
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
Center frequency in Hz for a notch filter. Used i.e. for line
noise suppression.
What: /sys/bus/iio/devices/iio:deviceX/in_temp_thermocouple_type
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
One of the following thermocouple types: B, E, J, K, N, R, S, T.

View File

@ -0,0 +1,19 @@
What: /sys/bus/iio/devices/iio:deviceX/buffer/length_align_bytes
KernelVersion: 5.4
Contact: linux-iio@vger.kernel.org
Description:
DMA buffers tend to have a alignment requirement for the
buffers. If this alignment requirement is not met samples might
be dropped from the buffer.
This property reports the alignment requirements in bytes.
This means that the buffer size in bytes needs to be a integer
multiple of the number reported by this file.
The alignment requirements in number of sample sets will depend
on the enabled channels and the bytes per channel. This means
that the alignment requirement in samples sets might change
depending on which and how many channels are enabled. Whereas
the alignment requirement reported in bytes by this property
will remain static and does not depend on which channels are
enabled.

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/accel/adi,adis16240.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ADIS16240 Programmable Impact Sensor and Recorder driver
maintainers:
- Alexandru Ardelean <alexandru.ardelean@analog.com>
description: |
ADIS16240 Programmable Impact Sensor and Recorder driver that supports
SPI interface.
https://www.analog.com/en/products/adis16240.html
properties:
compatible:
enum:
- adi,adis16240
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
/* Example for a SPI device node */
accelerometer@0 {
compatible = "adi,adis16240";
reg = <0>;
spi-max-frequency = <2500000>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
};
};

View File

@ -1,11 +1,14 @@
* Bosch BMA180 / BMA250 triaxial acceleration sensor
* Bosch BMA180 / BMA25x triaxial acceleration sensor
http://omapworld.com/BMA180_111_1002839.pdf
http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/bst-bma250-ds002-05.pdf
Required properties:
- compatible : should be "bosch,bma180" or "bosch,bma250"
- compatible : should be one of:
"bosch,bma180"
"bosch,bma250"
"bosch,bma254"
- reg : the I2C address of the sensor
Optional properties:

View File

@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/accel/bosch,bma400.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch BMA400 triaxial acceleration sensor
maintainers:
- Dan Robertson <dan@dlrobertson.com>
description: |
Acceleration and temperature iio sensors with an i2c interface
Specifications about the sensor can be found at:
https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMA400-DS000.pdf
properties:
compatible:
enum:
- bosch,bma400
reg:
maxItems: 1
vdd-supply:
description: phandle to the regulator that provides power to the accelerometer
vddio-supply:
description: phandle to the regulator that provides power to the sensor's IO
interrupts:
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
accelerometer@14 {
compatible = "bosch,bma400";
reg = <0x14>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
};
};

View File

@ -9,9 +9,16 @@ Required properties:
"kionix,kxtf9"
- reg: i2c slave address
Optional properties:
- mount-matrix: an optional 3x3 mounting rotation matrix
Example:
kxtf9@f {
compatible = "kionix,kxtf9";
reg = <0x0F>;
mount-matrix = "0", "1", "0",
"1", "0", "0",
"0", "0", "1";
};

View File

@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7091R5 4-Channel 12-Bit ADC
maintainers:
- Beniamin Bia <beniamin.bia@analog.com>
description: |
Analog Devices AD7091R5 4-Channel 12-Bit ADC
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf
properties:
compatible:
enum:
- adi,ad7091r5
reg:
maxItems: 1
vref-supply:
description:
Phandle to the vref power supply
interrupts:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@2f {
compatible = "adi,ad7091r5";
reg = <0x2f>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
};
};
...

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/lltc,ltc2496.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology / Analog Devices LTC2496 ADC
maintainers:
- Lars-Peter Clausen <lars@metafoo.de>
- Michael Hennerich <Michael.Hennerich@analog.com>
- Stefan Popa <stefan.popa@analog.com>
properties:
compatible:
enum:
- lltc,ltc2496
vref-supply:
description: phandle to an external regulator providing the reference voltage
allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
reg:
description: spi chipselect number according to the usual spi bindings
spi-max-frequency:
description: maximal spi bus frequency supported
required:
- compatible
- vref-supply
- reg
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "lltc,ltc2496";
reg = <0>;
vref-supply = <&ltc2496_reg>;
spi-max-frequency = <2000000>;
};
};

View File

@ -1,13 +0,0 @@
Device-Tree bindings for sigma delta modulator
Required properties:
- compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use
as a generic SD modulator if modulator not specified in compatible list.
- #io-channel-cells = <0>: See the IIO bindings section "IIO consumers".
Example node:
ads1202: adc {
compatible = "sd-modulator";
#io-channel-cells = <0>;
};

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/sigma-delta-modulator.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Device-Tree bindings for sigma delta modulator
maintainers:
- Arnaud Pouliquen <arnaud.pouliquen@st.com>
properties:
compatible:
description: |
"sd-modulator" can be used as a generic SD modulator,
if the modulator is not specified in the compatible list.
enum:
- sd-modulator
- ads1201
'#io-channel-cells':
const: 0
required:
- compatible
- '#io-channel-cells'
additionalProperties: false
examples:
- |
ads1202: adc {
compatible = "sd-modulator";
#io-channel-cells = <0>;
};
...

View File

@ -8,6 +8,7 @@ Required properties for the ADIS16480:
* "adi,adis16480"
* "adi,adis16485"
* "adi,adis16488"
* "adi,adis16490"
* "adi,adis16495-1"
* "adi,adis16495-2"
* "adi,adis16495-3"

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/pressure/asc,dlhl60d.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: All Sensors DLH series low voltage digital pressure sensors
maintainers:
- Tomislav Denis <tomislav.denis@avl.com>
description: |
Bindings for the All Sensors DLH series pressure sensors.
Specifications about the sensors can be found at:
http://www.allsensors.com/cad/DS-0355_Rev_B.PDF
properties:
compatible:
enum:
- asc,dlhl60d
- asc,dlhl60g
reg:
description: I2C device address
maxItems: 1
interrupts:
description: interrupt mapping for EOC(data ready) pin
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
pressure@29 {
compatible = "asc,dlhl60d";
reg = <0x29>;
interrupt-parent = <&gpio0>;
interrupts = <10 IRQ_TYPE_EDGE_RISING>;
};
};
...

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/parallax-ping.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Parallax PING))) and LaserPING range finder
maintainers:
- Andreas Klinger <ak@it-klinger.de>
description: |
Bit-banging driver using one GPIO:
- ping-gpios is raised by the driver to start measurement
- direction of ping-gpio is then switched into input with an interrupt
for receiving distance value as PWM signal
Specifications about the devices can be found at:
http://parallax.com/sites/default/files/downloads/28041-LaserPING-2m-Rangefinder-Guide.pdf
http://parallax.com/sites/default/files/downloads/28015-PING-Documentation-v1.6.pdf
properties:
compatible:
enum:
- parallax,ping
- parallax,laserping
ping-gpios:
description:
Definition of the GPIO for the triggering and echo (output and input)
This GPIO is set for about 5 us by the driver to tell the device it
should initiate the measurement cycle. Afterwards the GPIO is switched
to input direction with an interrupt. The device sets it and the
length of the input signal corresponds to the measured distance.
It needs to be an GPIO which is able to deliver an interrupt because
the time between two interrupts is measured in the driver.
See Documentation/devicetree/bindings/gpio/gpio.txt for information
on how to specify a consumer gpio.
maxItems: 1
required:
- compatible
- ping-gpios
examples:
- |
#include <dt-bindings/gpio/gpio.h>
proximity {
compatible = "parallax,laserping";
ping-gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
};

View File

@ -5,7 +5,10 @@ Maxim thermocouple support
Required properties:
- compatible: must be "maxim,max31855" or "maxim,max6675"
- compatible: must be "maxim,max6675" or one of the following:
"maxim,max31855k", "maxim,max31855j", "maxim,max31855n",
"maxim,max31855s", "maxim,max31855t", "maxim,max31855e",
"maxim,max31855r"; the generic "max,max31855" is deprecated.
- reg: SPI chip select number for the device
- spi-max-frequency: must be 4300000
- spi-cpha: must be defined for max6675 to enable SPI mode 1
@ -15,7 +18,7 @@ Required properties:
Example:
max31855@0 {
compatible = "maxim,max31855";
compatible = "maxim,max31855k";
reg = <0>;
spi-max-frequency = <4300000>;
};

View File

@ -109,6 +109,8 @@ patternProperties:
description: Artesyn Embedded Technologies Inc.
"^asahi-kasei,.*":
description: Asahi Kasei Corp.
"^asc,.*":
description: All Sensors Corporation
"^aspeed,.*":
description: ASPEED Technology Inc.
"^asus,.*":
@ -717,6 +719,8 @@ patternProperties:
description: Panasonic Corporation
"^parade,.*":
description: Parade Technologies Inc.
"^parallax,.*":
description: Parallax Inc.
"^pda,.*":
description: Precision Design Associates, Inc.
"^pericom,.*":

View File

@ -1,246 +0,0 @@
================================
Driver for active AVM Controller
================================
The driver provides a kernel capi2.0 Interface (kernelcapi) and
on top of this a User-Level-CAPI2.0-interface (capi)
and a driver to connect isdn4linux with CAPI2.0 (capidrv).
The lowlevel interface can be used to implement a CAPI2.0
also for passive cards since July 1999.
The author can be reached at calle@calle.in-berlin.de.
The command avmcapictrl is part of the isdn4k-utils.
t4-files can be found at ftp://ftp.avm.de/cardware/b1/linux/firmware
Currently supported cards:
- B1 ISA (all versions)
- B1 PCI
- T1/T1B (HEMA card)
- M1
- M2
- B1 PCMCIA
Installing
----------
You need at least /dev/capi20 to load the firmware.
::
mknod /dev/capi20 c 68 0
mknod /dev/capi20.00 c 68 1
mknod /dev/capi20.01 c 68 2
.
.
.
mknod /dev/capi20.19 c 68 20
Running
-------
To use the card you need the t4-files to download the firmware.
AVM GmbH provides several t4-files for the different D-channel
protocols (b1.t4 for Euro-ISDN). Install these file in /lib/isdn.
if you configure as modules load the modules this way::
insmod /lib/modules/current/misc/capiutil.o
insmod /lib/modules/current/misc/b1.o
insmod /lib/modules/current/misc/kernelcapi.o
insmod /lib/modules/current/misc/capidrv.o
insmod /lib/modules/current/misc/capi.o
if you have an B1-PCI card load the module b1pci.o::
insmod /lib/modules/current/misc/b1pci.o
and load the firmware with::
avmcapictrl load /lib/isdn/b1.t4 1
if you have an B1-ISA card load the module b1isa.o
and add the card by calling::
avmcapictrl add 0x150 15
and load the firmware by calling::
avmcapictrl load /lib/isdn/b1.t4 1
if you have an T1-ISA card load the module t1isa.o
and add the card by calling::
avmcapictrl add 0x450 15 T1 0
and load the firmware by calling::
avmcapictrl load /lib/isdn/t1.t4 1
if you have an PCMCIA card (B1/M1/M2) load the module b1pcmcia.o
before you insert the card.
Leased Lines with B1
--------------------
Init card and load firmware.
For an D64S use "FV: 1" as phone number
For an D64S2 use "FV: 1" and "FV: 2" for multilink
or "FV: 1,2" to use CAPI channel bundling.
/proc-Interface
-----------------
/proc/capi::
dr-xr-xr-x 2 root root 0 Jul 1 14:03 .
dr-xr-xr-x 82 root root 0 Jun 30 19:08 ..
-r--r--r-- 1 root root 0 Jul 1 14:03 applications
-r--r--r-- 1 root root 0 Jul 1 14:03 applstats
-r--r--r-- 1 root root 0 Jul 1 14:03 capi20
-r--r--r-- 1 root root 0 Jul 1 14:03 capidrv
-r--r--r-- 1 root root 0 Jul 1 14:03 controller
-r--r--r-- 1 root root 0 Jul 1 14:03 contrstats
-r--r--r-- 1 root root 0 Jul 1 14:03 driver
-r--r--r-- 1 root root 0 Jul 1 14:03 ncci
-r--r--r-- 1 root root 0 Jul 1 14:03 users
/proc/capi/applications:
applid level3cnt datablkcnt datablklen ncci-cnt recvqueuelen
level3cnt:
capi_register parameter
datablkcnt:
capi_register parameter
ncci-cnt:
current number of nccis (connections)
recvqueuelen:
number of messages on receive queue
for example::
1 -2 16 2048 1 0
2 2 7 2048 1 0
/proc/capi/applstats:
applid recvctlmsg nrecvdatamsg nsentctlmsg nsentdatamsg
recvctlmsg:
capi messages received without DATA_B3_IND
recvdatamsg:
capi DATA_B3_IND received
sentctlmsg:
capi messages sent without DATA_B3_REQ
sentdatamsg:
capi DATA_B3_REQ sent
for example::
1 2057 1699 1721 1699
/proc/capi/capi20: statistics of capi.o (/dev/capi20)
minor nopen nrecvdropmsg nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg
minor:
minor device number of capi device
nopen:
number of calls to devices open
nrecvdropmsg:
capi messages dropped (messages in recvqueue in close)
nrecvctlmsg:
capi messages received without DATA_B3_IND
nrecvdatamsg:
capi DATA_B3_IND received
nsentctlmsg:
capi messages sent without DATA_B3_REQ
nsentdatamsg:
capi DATA_B3_REQ sent
for example::
1 2 18 0 16 2
/proc/capi/capidrv: statistics of capidrv.o (capi messages)
nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg
nrecvctlmsg:
capi messages received without DATA_B3_IND
nrecvdatamsg:
capi DATA_B3_IND received
nsentctlmsg:
capi messages sent without DATA_B3_REQ
nsentdatamsg:
capi DATA_B3_REQ sent
for example:
2780 2226 2256 2226
/proc/capi/controller:
controller drivername state cardname controllerinfo
for example::
1 b1pci running b1pci-e000 B1 3.07-01 0xe000 19
2 t1isa running t1isa-450 B1 3.07-01 0x450 11 0
3 b1pcmcia running m2-150 B1 3.07-01 0x150 5
/proc/capi/contrstats:
controller nrecvctlmsg nrecvdatamsg sentctlmsg sentdatamsg
nrecvctlmsg:
capi messages received without DATA_B3_IND
nrecvdatamsg:
capi DATA_B3_IND received
nsentctlmsg:
capi messages sent without DATA_B3_REQ
nsentdatamsg:
capi DATA_B3_REQ sent
for example::
1 2845 2272 2310 2274
2 2 0 2 0
3 2 0 2 0
/proc/capi/driver:
drivername ncontroller
for example::
b1pci 1
t1isa 1
b1pcmcia 1
b1isa 0
/proc/capi/ncci:
apllid ncci winsize sendwindow
for example::
1 0x10101 8 0
/proc/capi/users: kernelmodules that use the kernelcapi.
name
for example::
capidrv
capi20
Questions
---------
Check out the FAQ (ftp.isdn4linux.de) or subscribe to the
linux-avmb1@calle.in-berlin.de mailing list by sending
a mail to majordomo@calle.in-berlin.de with
subscribe linux-avmb1
in the body.
German documentation and several scripts can be found at
ftp://ftp.avm.de/cardware/b1/linux/
Bugs
----
If you find any please let me know.
Enjoy,
Carsten Paeth (calle@calle.in-berlin.de)

View File

@ -1,465 +0,0 @@
==========================
GigaSet 307x Device Driver
==========================
1. Requirements
=================
1.1. Hardware
-------------
This driver supports the connection of the Gigaset 307x/417x family of
ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB
connection. The following devices are reported to be compatible:
Bases:
- Siemens Gigaset 3070/3075 isdn
- Siemens Gigaset 4170/4175 isdn
- Siemens Gigaset SX205/255
- Siemens Gigaset SX353
- T-Com Sinus 45 [AB] isdn
- T-Com Sinus 721X[A] [SE]
- Vox Chicago 390 ISDN (KPN Telecom)
RS232 data boxes:
- Siemens Gigaset M101 Data
- T-Com Sinus 45 Data 1
USB data boxes:
- Siemens Gigaset M105 Data
- Siemens Gigaset USB Adapter DECT
- T-Com Sinus 45 Data 2
- T-Com Sinus 721 data
- Chicago 390 USB (KPN)
See also http://www.erbze.info/sinus_gigaset.htm
(archived at https://web.archive.org/web/20100717020421/http://www.erbze.info:80/sinus_gigaset.htm ) and
http://gigaset307x.sourceforge.net/
We had also reports from users of Gigaset M105 who could use the drivers
with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.5.)
If you have another device that works with our driver, please let us know.
Chances of getting an USB device to work are good if the output of::
lsusb
at the command line contains one of the following::
ID 0681:0001
ID 0681:0002
ID 0681:0009
ID 0681:0021
ID 0681:0022
1.2. Software
-------------
The driver works with the Kernel CAPI subsystem and can be used with any
software which is able to use CAPI 2.0 for ISDN connections (voice or data).
There are some user space tools available at
https://sourceforge.net/projects/gigaset307x/
which provide access to additional device specific functions like SMS,
phonebook or call journal.
2. How to use the driver
==========================
2.1. Modules
------------
For the devices to work, the proper kernel modules have to be loaded.
This normally happens automatically when the system detects the USB
device (base, M105) or when the line discipline is attached (M101). It
can also be triggered manually using the modprobe(8) command, for example
for troubleshooting or to pass module parameters.
The module ser_gigaset provides a serial line discipline N_GIGASET_M101
which uses the regular serial port driver to access the device, and must
therefore be attached to the serial device to which the M101 is connected.
The ldattach(8) command (included in util-linux-ng release 2.14 or later)
can be used for that purpose, for example::
ldattach GIGASET_M101 /dev/ttyS1
This will open the device file, attach the line discipline to it, and
then sleep in the background, keeping the device open so that the line
discipline remains active. To deactivate it, kill the daemon, for example
with::
killall ldattach
before disconnecting the device. To have this happen automatically at
system startup/shutdown on an LSB compatible system, create and activate
an appropriate LSB startup script /etc/init.d/gigaset. (The init name
'gigaset' is officially assigned to this project by LANANA.)
Alternatively, just add the 'ldattach' command line to /etc/rc.local.
The modules accept the following parameters:
=============== ========== ==========================================
Module Parameter Meaning
gigaset debug debug level (see section 3.2.)
startmode initial operation mode (see section 2.5.):
bas_gigaset ) 1=CAPI (default), 0=Unimodem
ser_gigaset )
usb_gigaset ) cidmode initial Call-ID mode setting (see section
2.5.): 1=on (default), 0=off
=============== ========== ==========================================
Depending on your distribution you may want to create a separate module
configuration file like /etc/modprobe.d/gigaset.conf for these.
2.2. Device nodes for user space programs
-----------------------------------------
The device can be accessed from user space (eg. by the user space tools
mentioned in 1.2.) through the device nodes:
- /dev/ttyGS0 for M101 (RS232 data boxes)
- /dev/ttyGU0 for M105 (USB data boxes)
- /dev/ttyGB0 for the base driver (direct USB connection)
If you connect more than one device of a type, they will get consecutive
device nodes, eg. /dev/ttyGU1 for a second M105.
You can also set a "default device" for the user space tools to use when
no device node is given as parameter, by creating a symlink /dev/ttyG to
one of them, eg.::
ln -s /dev/ttyGB0 /dev/ttyG
The devices accept the following device specific ioctl calls
(defined in gigaset_dev.h):
``ioctl(int fd, GIGASET_REDIR, int *cmd);``
If cmd==1, the device is set to be controlled exclusively through the
character device node; access from the ISDN subsystem is blocked.
If cmd==0, the device is set to be used from the ISDN subsystem and does
not communicate through the character device node.
``ioctl(int fd, GIGASET_CONFIG, int *cmd);``
(ser_gigaset and usb_gigaset only)
If cmd==1, the device is set to adapter configuration mode where commands
are interpreted by the M10x DECT adapter itself instead of being
forwarded to the base station. In this mode, the device accepts the
commands described in Siemens document "AT-Kommando Alignment M10x Data"
for setting the operation mode, associating with a base station and
querying parameters like field strengh and signal quality.
Note that there is no ioctl command for leaving adapter configuration
mode and returning to regular operation. In order to leave adapter
configuration mode, write the command ATO to the device.
``ioctl(int fd, GIGASET_BRKCHARS, unsigned char brkchars[6]);``
(usb_gigaset only)
Set the break characters on an M105's internal serial adapter to the six
bytes stored in brkchars[]. Unused bytes should be set to zero.
ioctl(int fd, GIGASET_VERSION, unsigned version[4]);
Retrieve version information from the driver. version[0] must be set to
one of:
- GIGVER_DRIVER: retrieve driver version
- GIGVER_COMPAT: retrieve interface compatibility version
- GIGVER_FWBASE: retrieve the firmware version of the base
Upon return, version[] is filled with the requested version information.
2.3. CAPI
---------
The devices will show up as CAPI controllers as soon as the
corresponding driver module is loaded, and can then be used with
CAPI 2.0 kernel and user space applications. For user space access,
the module capi.ko must be loaded.
Most distributions handle loading and unloading of the various CAPI
modules automatically via the command capiinit(1) from the capi4k-utils
package or a similar mechanism. Note that capiinit(1) cannot unload the
Gigaset drivers because it doesn't support more than one module per
driver.
2.5. Unimodem mode
------------------
In this mode the device works like a modem connected to a serial port
(the /dev/ttyGU0, ... mentioned above) which understands the commands::
ATZ init, reset
=> OK or ERROR
ATD
ATDT dial
=> OK, CONNECT,
BUSY,
NO DIAL TONE,
NO CARRIER,
NO ANSWER
<pause>+++<pause> change to command mode when connected
ATH hangup
You can use some configuration tool of your distribution to configure this
"modem" or configure pppd/wvdial manually. There are some example ppp
configuration files and chat scripts in the gigaset-VERSION/ppp directory
in the driver packages from https://sourceforge.net/projects/gigaset307x/.
Please note that the USB drivers are not able to change the state of the
control lines. This means you must use "Stupid Mode" if you are using
wvdial or you should use the nocrtscts option of pppd.
You must also assure that the ppp_async module is loaded with the parameter
flag_time=0. You can do this e.g. by adding a line like::
options ppp_async flag_time=0
to an appropriate module configuration file, like::
/etc/modprobe.d/gigaset.conf.
Unimodem mode is needed for making some devices [e.g. SX100] work which
do not support the regular Gigaset command set. If debug output (see
section 3.2.) shows something like this when dialing::
CMD Received: ERROR
Available Params: 0
Connection State: 0, Response: -1
gigaset_process_response: resp_code -1 in ConState 0 !
Timeout occurred
then switching to unimodem mode may help.
If you have installed the command line tool gigacontr, you can enter
unimodem mode using::
gigacontr --mode unimodem
You can switch back using::
gigacontr --mode isdn
You can also put the driver directly into Unimodem mode when it's loaded,
by passing the module parameter startmode=0 to the hardware specific
module, e.g.::
modprobe usb_gigaset startmode=0
or by adding a line like::
options usb_gigaset startmode=0
to an appropriate module configuration file, like::
/etc/modprobe.d/gigaset.conf
2.6. Call-ID (CID) mode
-----------------------
Call-IDs are numbers used to tag commands to, and responses from, the
Gigaset base in order to support the simultaneous handling of multiple
ISDN calls. Their use can be enabled ("CID mode") or disabled ("Unimodem
mode"). Without Call-IDs (in Unimodem mode), only a very limited set of
functions is available. It allows outgoing data connections only, but
does not signal incoming calls or other base events.
DECT cordless data devices (M10x) permanently occupy the cordless
connection to the base while Call-IDs are activated. As the Gigaset
bases only support one DECT data connection at a time, this prevents
other DECT cordless data devices from accessing the base.
During active operation, the driver switches to the necessary mode
automatically. However, for the reasons above, the mode chosen when
the device is not in use (idle) can be selected by the user.
- If you want to receive incoming calls, you can use the default
settings (CID mode).
- If you have several DECT data devices (M10x) which you want to use
in turn, select Unimodem mode by passing the parameter "cidmode=0" to
the appropriate driver module (ser_gigaset or usb_gigaset).
If you want both of these at once, you are out of luck.
You can also use the tty class parameter "cidmode" of the device to
change its CID mode while the driver is loaded, eg.::
echo 0 > /sys/class/tty/ttyGU0/cidmode
2.7. Dialing Numbers
--------------------
provided by an application for dialing out must
be a public network number according to the local dialing plan, without
any dial prefix for getting an outside line.
Internal calls can be made by providing an internal extension number
prefixed with ``**`` (two asterisks) as the called party number. So to dial
eg. the first registered DECT handset, give ``**11`` as the called party
number. Dialing ``***`` (three asterisks) calls all extensions
simultaneously (global call).
Unimodem mode does not support internal calls.
2.8. Unregistered Wireless Devices (M101/M105)
----------------------------------------------
The main purpose of the ser_gigaset and usb_gigaset drivers is to allow
the M101 and M105 wireless devices to be used as ISDN devices for ISDN
connections through a Gigaset base. Therefore they assume that the device
is registered to a DECT base.
If the M101/M105 device is not registered to a base, initialization of
the device fails, and a corresponding error message is logged by the
driver. In that situation, a restricted set of functions is available
which includes, in particular, those necessary for registering the device
to a base or for switching it between Fixed Part and Portable Part
modes. See the gigacontr(8) manpage for details.
3. Troubleshooting
====================
3.1. Solutions to frequently reported problems
----------------------------------------------
Problem:
You have a slow provider and isdn4linux gives up dialing too early.
Solution:
Load the isdn module using the dialtimeout option. You can do this e.g.
by adding a line like::
options isdn dialtimeout=15
to /etc/modprobe.d/gigaset.conf or a similar file.
Problem:
The isdnlog program emits error messages or just doesn't work.
Solution:
Isdnlog supports only the HiSax driver. Do not attempt to use it with
other drivers such as Gigaset.
Problem:
You have two or more DECT data adapters (M101/M105) and only the
first one you turn on works.
Solution:
Select Unimodem mode for all DECT data adapters. (see section 2.5.)
Problem:
Messages like this::
usb_gigaset 3-2:1.0: Could not initialize the device.
appear in your syslog.
Solution:
Check whether your M10x wireless device is correctly registered to the
Gigaset base. (see section 2.7.)
3.2. Telling the driver to provide more information
---------------------------------------------------
Building the driver with the "Gigaset debugging" kernel configuration
option (CONFIG_GIGASET_DEBUG) gives it the ability to produce additional
information useful for debugging.
You can control the amount of debugging information the driver produces by
writing an appropriate value to /sys/module/gigaset/parameters/debug,
e.g.::
echo 0 > /sys/module/gigaset/parameters/debug
switches off debugging output completely,
::
echo 0x302020 > /sys/module/gigaset/parameters/debug
enables a reasonable set of debugging output messages. These values are
bit patterns where every bit controls a certain type of debugging output.
See the constants DEBUG_* in the source file gigaset.h for details.
The initial value can be set using the debug parameter when loading the
module "gigaset", e.g. by adding a line::
options gigaset debug=0
to your module configuration file, eg. /etc/modprobe.d/gigaset.conf
Generated debugging information can be found
- as output of the command::
dmesg
- in system log files written by your syslog daemon, usually
in /var/log/, e.g. /var/log/messages.
3.3. Reporting problems and bugs
--------------------------------
If you can't solve problems with the driver on your own, feel free to
use one of the forums, bug trackers, or mailing lists on
https://sourceforge.net/projects/gigaset307x
or write an electronic mail to the maintainers.
Try to provide as much information as possible, such as
- distribution
- kernel version (uname -r)
- gcc version (gcc --version)
- hardware architecture (uname -m, ...)
- type and firmware version of your device (base and wireless module,
if any)
- output of "lsusb -v" (if using an USB device)
- error messages
- relevant system log messages (it would help if you activate debug
output as described in 3.2.)
For help with general configuration problems not specific to our driver,
such as isdn4linux and network configuration issues, please refer to the
appropriate forums and newsgroups.
3.4. Reporting problem solutions
--------------------------------
If you solved a problem with our drivers, wrote startup scripts for your
distribution, ... feel free to contact us (using one of the places
mentioned in 3.3.). We'd like to add scripts, hints, documentation
to the driver and/or the project web page.
4. Links, other software
==========================
- Sourceforge project developing this driver and associated tools
https://sourceforge.net/projects/gigaset307x
- Yahoo! Group on the Siemens Gigaset family of devices
https://de.groups.yahoo.com/group/Siemens-Gigaset
- Siemens Gigaset/T-Sinus compatibility table
http://www.erbze.info/sinus_gigaset.htm
(archived at https://web.archive.org/web/20100717020421/http://www.erbze.info:80/sinus_gigaset.htm )
5. Credits
============
Thanks to
Karsten Keil
for his help with isdn4linux
Deti Fliegl
for his base driver code
Dennis Dietrich
for his kernel 2.6 patches
Andreas Rummel
for his work and logs to get unimodem mode working
Andreas Degert
for his logs and patches to get cx 100 working
Dietrich Feist
for his generous donation of one M105 and two M101 cordless adapters
Christoph Schweers
for his generous donation of a M34 device
and all the other people who sent logs and other information.

View File

@ -1,196 +0,0 @@
============
Hysdn Driver
============
The hysdn driver has been written by
Werner Cornelius (werner@isdn4linux.de or werner@titro.de)
for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
under the GNU General Public License.
The CAPI 2.0-support was added by Ulrich Albrecht (ualbrecht@hypercope.de)
for Hypercope GmbH Aachen, Germany.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
.. Table of contents
1. About the driver
2. Loading/Unloading the driver
3. Entries in the /proc filesystem
4. The /proc/net/hysdn/cardconfX file
5. The /proc/net/hysdn/cardlogX file
6. Where to get additional info and help
1. About the driver
===================
The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active
PCI isdn cards Champ, Ergo and Metro. To enable support for this cards
enable ISDN support in the kernel config and support for HYSDN cards in
the active cards submenu. The driver may only be compiled and used if
support for loadable modules and the process filesystem have been enabled.
These cards provide two different interfaces to the kernel. Without the
optional CAPI 2.0 support, they register as ethernet card. IP-routing
to a ISDN-destination is performed on the card itself. All necessary
handlers for various protocols like ppp and others as well as config info
and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de.
With CAPI 2.0 support enabled, the card can also be used as a CAPI 2.0
compliant devices with either CAPI 2.0 applications
(check isdn4k-utils) or -using the capidrv module- as a regular
isdn4linux device. This is done via the same mechanism as with the
active AVM cards and in fact uses the same module.
2. Loading/Unloading the driver
===============================
The module has no command line parameters and auto detects up to 10 cards
in the id-range 0-9.
If a loaded driver shall be unloaded all open files in the /proc/net/hysdn
subdir need to be closed and all ethernet interfaces allocated by this
driver must be shut down. Otherwise the module counter will avoid a module
unload.
If you are using the CAPI 2.0-interface, make sure to load/modprobe the
kernelcapi-module first.
If you plan to use the capidrv-link to isdn4linux, make sure to load
capidrv.o after all modules using this driver (i.e. after hysdn and
any avm-specific modules).
3. Entries in the /proc filesystem
==================================
When the module has been loaded it adds the directory hysdn in the
/proc/net tree. This directory contains exactly 2 file entries for each
card. One is called cardconfX and the other cardlogX, where X is the
card id number from 0 to 9.
The cards are numbered in the order found in the PCI config data.
4. The /proc/net/hysdn/cardconfX file
=====================================
This file may be read to get by everyone to get info about the cards type,
actual state, available features and used resources.
The first 3 entries (id, bus and slot) are PCI info fields, the following
type field gives the information about the cards type:
- 4 -> Ergo card (server card with 2 b-chans)
- 5 -> Metro card (server card with 4 or 8 b-chans)
- 6 -> Champ card (client card with 2 b-chans)
The following 3 fields show the hardware assignments for irq, iobase and the
dual ported memory (dp-mem).
The fields b-chans and fax-chans announce the available card resources of
this types for the user.
The state variable indicates the actual drivers state for this card with the
following assignments.
- 0 -> card has not been booted since driver load
- 1 -> card booting is actually in progess
- 2 -> card is in an error state due to a previous boot failure
- 3 -> card is booted and active
And the last field (device) shows the name of the ethernet device assigned
to this card. Up to the first successful boot this field only shows a -
to tell that no net device has been allocated up to now. Once a net device
has been allocated it remains assigned to this card, even if a card is
rebooted and an boot error occurs.
Writing to the cardconfX file boots the card or transfers config lines to
the cards firmware. The type of data is automatically detected when the
first data is written. Only root has write access to this file.
The firmware boot files are normally called hyclient.pof for client cards
and hyserver.pof for server cards.
After successfully writing the boot file, complete config files or single
config lines may be copied to this file.
If an error occurs the return value given to the writing process has the
following additional codes (decimal):
==== ============================================
1000 Another process is currently bootng the card
1001 Invalid firmware header
1002 Boards dual-port RAM test failed
1003 Internal firmware handler error
1004 Boot image size invalid
1005 First boot stage (bootstrap loader) failed
1006 Second boot stage failure
1007 Timeout waiting for card ready during boot
1008 Operation only allowed in booted state
1009 Config line too long
1010 Invalid channel number
1011 Timeout sending config data
==== ============================================
Additional info about error reasons may be fetched from the log output.
5. The /proc/net/hysdn/cardlogX file
====================================
The cardlogX file entry may be opened multiple for reading by everyone to
get the cards and drivers log data. Card messages always start with the
keyword LOG. All other lines are output from the driver.
The driver log data may be redirected to the syslog by selecting the
appropriate bitmask. The cards log messages will always be send to this
interface but never to the syslog.
A root user may write a decimal or hex (with 0x) value t this file to select
desired output options. As mentioned above the cards log dat is always
written to the cardlog file independent of the following options only used
to check and debug the driver itself:
For example::
echo "0x34560078" > /proc/net/hysdn/cardlog0
to output the hex log mask 34560078 for card 0.
The written value is regarded as an unsigned 32-Bit value, bit ored for
desired output. The following bits are already assigned:
========== ============================================================
0x80000000 All driver log data is alternatively via syslog
0x00000001 Log memory allocation errors
0x00000010 Firmware load start and close are logged
0x00000020 Log firmware record parser
0x00000040 Log every firmware write actions
0x00000080 Log all card related boot messages
0x00000100 Output all config data sent for debugging purposes
0x00000200 Only non comment config lines are shown wth channel
0x00000400 Additional conf log output
0x00001000 Log the asynchronous scheduler actions (config and log)
0x00100000 Log all open and close actions to /proc/net/hysdn/card files
0x00200000 Log all actions from /proc file entries
0x00010000 Log network interface init and deinit
========== ============================================================
6. Where to get additional info and help
========================================
If you have any problems concerning the driver or configuration contact
the Hypercope support team (support@hypercope.de) and or the authors
Werner Cornelius (werner@isdn4linux or cornelius@titro.de) or
Ulrich Albrecht (ualbrecht@hypercope.de).

View File

@ -9,9 +9,6 @@ ISDN
interface_capi
avmb1
gigaset
hysdn
m_isdn
credits

View File

@ -26,13 +26,6 @@ This standard is freely available from https://www.capi.org.
2. Driver and Device Registration
=================================
CAPI drivers optionally register themselves with Kernel CAPI by calling the
Kernel CAPI function register_capi_driver() with a pointer to a struct
capi_driver. This structure must be filled with the name and revision of the
driver, and optionally a pointer to a callback function, add_card(). The
registration can be revoked by calling the function unregister_capi_driver()
with a pointer to the same struct capi_driver.
CAPI drivers must register each of the ISDN devices they control with Kernel
CAPI by calling the Kernel CAPI function attach_capi_ctr() with a pointer to a
struct capi_ctr before they can be used. This structure must be filled with
@ -89,9 +82,6 @@ register_capi_driver():
the name of the driver, as a zero-terminated ASCII string
``char revision[32]``
the revision number of the driver, as a zero-terminated ASCII string
``int (*add_card)(struct capi_driver *driver, capicardparams *data)``
a callback function pointer (may be NULL)
4.2 struct capi_ctr
-------------------
@ -178,12 +168,6 @@ to be set by the driver before calling attach_capi_ctr():
pointer to a callback function returning the entry for the device in
the CAPI controller info table, /proc/capi/controller
``const struct file_operations *proc_fops``
pointers to callback functions for the device's proc file
system entry, /proc/capi/controllers/<n>; pointer to the device's
capi_ctr structure is available from struct proc_dir_entry::data
which is available from struct inode.
Note:
Callback functions except send_message() are never called in interrupt
context.
@ -267,25 +251,10 @@ _cmstruct alternative representation for CAPI parameters of type 'struct'
_cmsg structure members.
=========== =================================================================
Functions capi_cmsg2message() and capi_message2cmsg() are provided to convert
messages between their transport encoding described in the CAPI 2.0 standard
and their _cmsg structure representation. Note that capi_cmsg2message() does
not know or check the size of its destination buffer. The caller must make
sure it is big enough to accommodate the resulting CAPI message.
5. Lower Layer Interface Functions
==================================
(declared in <linux/isdn/capilli.h>)
::
void register_capi_driver(struct capi_driver *drvr)
void unregister_capi_driver(struct capi_driver *drvr)
register/unregister a driver with Kernel CAPI
::
int attach_capi_ctr(struct capi_ctr *ctrlr)
@ -300,13 +269,6 @@ register/unregister a device (controller) with Kernel CAPI
signal controller ready/not ready
::
void capi_ctr_suspend_output(struct capi_ctr *ctrlr)
void capi_ctr_resume_output(struct capi_ctr *ctrlr)
signal suspend/resume
::
void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid,
@ -319,21 +281,6 @@ for forwarding to the specified application
6. Helper Functions and Macros
==============================
Library functions (from <linux/isdn/capilli.h>):
::
void capilib_new_ncci(struct list_head *head, u16 applid,
u32 ncci, u32 winsize)
void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
void capilib_release_appl(struct list_head *head, u16 applid)
void capilib_release(struct list_head *head)
void capilib_data_b3_conf(struct list_head *head, u16 applid,
u32 ncci, u16 msgid)
u16 capilib_data_b3_req(struct list_head *head, u16 applid,
u32 ncci, u16 msgid)
Macros to extract/set element values from/in a CAPI message header
(from <linux/isdn/capiutil.h>):
@ -357,24 +304,6 @@ CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16)
Library functions for working with _cmsg structures
(from <linux/isdn/capiutil.h>):
``unsigned capi_cmsg2message(_cmsg *cmsg, u8 *msg)``
Assembles a CAPI 2.0 message from the parameters in ``*cmsg``,
storing the result in ``*msg``.
``unsigned capi_message2cmsg(_cmsg *cmsg, u8 *msg)``
Disassembles the CAPI 2.0 message in ``*msg``, storing the parameters
in ``*cmsg``.
``unsigned capi_cmsg_header(_cmsg *cmsg, u16 ApplId, u8 Command, u8 Subcommand, u16 Messagenumber, u32 Controller)``
Fills the header part and address field of the _cmsg structure ``*cmsg``
with the given values, zeroing the remainder of the structure so only
parameters with non-default values need to be changed before sending
the message.
``void capi_cmsg_answer(_cmsg *cmsg)``
Sets the low bit of the Subcommand field in ``*cmsg``, thereby
converting ``_REQ`` to ``_CONF`` and ``_IND`` to ``_RESP``.
``char *capi_cmd2str(u8 Command, u8 Subcommand)``
Returns the CAPI 2.0 message name corresponding to the given command
and subcommand values, as a static ASCII string. The return value may

View File

@ -132,7 +132,6 @@ Code Seq# Include File Comments
'F' 80-8F linux/arcfb.h conflict!
'F' DD video/sstfb.h conflict!
'G' 00-3F drivers/misc/sgi-gru/grulib.h conflict!
'G' 00-0F linux/gigaset_dev.h conflict!
'H' 00-7F linux/hiddev.h conflict!
'H' 00-0F linux/hidraw.h conflict!
'H' 01 linux/mei.h conflict!

View File

@ -674,6 +674,14 @@ S: Maintained
F: Documentation/i2c/busses/i2c-ali1563.rst
F: drivers/i2c/busses/i2c-ali1563.c
ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER
M: Tomislav Denis <tomislav.denis@avl.com>
W: http://www.allsensors.com/
S: Maintained
L: linux-iio@vger.kernel.org
F: drivers/iio/pressure/dlhl60d.c
F: Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml
ALLEGRO DVT VIDEO IP CORE DRIVER
M: Michael Tretter <m.tretter@pengutronix.de>
R: Pengutronix Kernel Team <kernel@pengutronix.de>
@ -907,6 +915,14 @@ S: Supported
F: drivers/iio/dac/ad5758.c
F: Documentation/devicetree/bindings/iio/dac/ad5758.txt
ANALOG DEVICES INC AD7091R5 DRIVER
M: Beniamin Bia <beniamin.bia@analog.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7091r5.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
ANALOG DEVICES INC AD7124 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-iio@vger.kernel.org
@ -1061,7 +1077,7 @@ S: Supported
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc2497*
F: drivers/iio/adc/ltc249*
X: drivers/iio/*/adjd*
F: drivers/staging/iio/*/ad*
@ -3116,6 +3132,13 @@ S: Supported
F: drivers/net/bonding/
F: include/uapi/linux/if_bonding.h
BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
M: Dan Robertson <dan@dlrobertson.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/accel/bma400*
F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
BPF (Safe dynamic programs and tools)
M: Alexei Starovoitov <ast@kernel.org>
M: Daniel Borkmann <daniel@iogearbox.net>
@ -8862,7 +8885,7 @@ S: Maintained
F: drivers/isdn/mISDN
F: drivers/isdn/hardware
ISDN/CAPI SUBSYSTEM
ISDN/CMTP OVER BLUETOOTH
M: Karsten Keil <isdn@linux-pingi.de>
L: isdn4linux@listserv.isdn4linux.de (subscribers-only)
L: netdev@vger.kernel.org
@ -8870,7 +8893,6 @@ W: http://www.isdn4linux.de
S: Odd Fixes
F: Documentation/isdn/
F: drivers/isdn/capi/
F: drivers/staging/isdn/
F: net/bluetooth/cmtp/
F: include/linux/isdn/
F: include/uapi/linux/isdn/
@ -12528,6 +12550,13 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/panasonic-laptop.c
PARALLAX PING IIO SENSOR DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/proximity/parallax-ping.yaml
F: drivers/iio/proximity/ping.c
PARALLEL LCD/KEYPAD PANEL DRIVER
M: Willy Tarreau <willy@haproxy.com>
M: Ksenija Stanojevic <ksenija.stanojevic@gmail.com>

View File

@ -89,13 +89,13 @@ config ADXL372_I2C
module will be called adxl372_i2c.
config BMA180
tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver"
tristate "Bosch BMA180/BMA25x 3-Axis Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Bosch BMA180 or
BMA250 triaxial acceleration sensor.
BMA25x triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma180.
@ -112,6 +112,22 @@ config BMA220
To compile this driver as a module, choose M here: the
module will be called bma220_spi.
config BMA400
tristate "Bosch BMA400 3-Axis Accelerometer Driver"
select REGMAP
select BMA400_I2C if I2C
help
Say Y here if you want to build a driver for the Bosch BMA400
triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma400_core and you will also get
bma400_i2c if I2C is enabled.
config BMA400_I2C
tristate
depends on BMA400
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
select IIO_BUFFER

View File

@ -14,6 +14,8 @@ obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMA400) += bma400_core.o
obj-$(CONFIG_BMA400_I2C) += bma400_i2c.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o

View File

@ -233,6 +233,12 @@ static const char * const adis16201_status_error_msgs[] = {
[ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
};
static const struct adis_timeout adis16201_timeouts = {
.reset_ms = ADIS16201_STARTUP_DELAY_MS,
.sw_reset_ms = ADIS16201_STARTUP_DELAY_MS,
.self_test_ms = ADIS16201_STARTUP_DELAY_MS,
};
static const struct adis_data adis16201_data = {
.read_delay = 20,
.msc_ctrl_reg = ADIS16201_MSC_CTRL_REG,
@ -241,7 +247,7 @@ static const struct adis_data adis16201_data = {
.self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
.self_test_no_autoclear = true,
.startup_delay = ADIS16201_STARTUP_DELAY_MS,
.timeouts = &adis16201_timeouts,
.status_error_msgs = adis16201_status_error_msgs,
.status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) |

View File

@ -243,6 +243,12 @@ static const char * const adis16209_status_error_msgs[] = {
[ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
};
static const struct adis_timeout adis16209_timeouts = {
.reset_ms = ADIS16209_STARTUP_DELAY_MS,
.self_test_ms = ADIS16209_STARTUP_DELAY_MS,
.sw_reset_ms = ADIS16209_STARTUP_DELAY_MS,
};
static const struct adis_data adis16209_data = {
.read_delay = 30,
.msc_ctrl_reg = ADIS16209_MSC_CTRL_REG,
@ -251,7 +257,7 @@ static const struct adis_data adis16209_data = {
.self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
.self_test_no_autoclear = true,
.startup_delay = ADIS16209_STARTUP_DELAY_MS,
.timeouts = &adis16209_timeouts,
.status_error_msgs = adis16209_status_error_msgs,
.status_error_mask = BIT(ADIS16209_STAT_SELFTEST_FAIL_BIT) |

View File

@ -9,6 +9,7 @@
* SPI is not supported by driver
* 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>
@ -18,6 +19,7 @@
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/iio/iio.h>
@ -33,17 +35,20 @@
enum chip_ids {
BMA180,
BMA250,
BMA254,
};
struct bma180_data;
struct bma180_part_info {
u8 chip_id;
const struct iio_chan_spec *channels;
unsigned int num_channels;
const int *scale_table;
unsigned int num_scales;
const int *bw_table;
unsigned int num_bw;
int center_temp;
u8 int_reset_reg, int_reset_mask;
u8 sleep_reg, sleep_mask;
@ -51,6 +56,7 @@ struct bma180_part_info {
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;
int (*chip_config)(struct bma180_data *data);
@ -89,6 +95,8 @@ struct bma180_part_info {
#define BMA180_RESET_VAL 0xb6
#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
@ -109,7 +117,26 @@ struct bma180_part_info {
#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;
struct i2c_client *client;
struct iio_trigger *trig;
const struct bma180_part_info *part_info;
@ -132,8 +159,8 @@ enum bma180_chan {
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 bma250_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
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,
0, 0, 306458 };
static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan)
@ -307,8 +334,11 @@ static int bma180_chip_init(struct bma180_data *data)
if (ret < 0)
return ret;
if (ret != BMA180_ID_REG_VAL)
if (ret != data->part_info->chip_id) {
dev_err(&data->client->dev, "wrong chip ID %d expected %d\n",
ret, data->part_info->chip_id);
return -ENODEV;
}
ret = bma180_soft_reset(data);
if (ret)
@ -355,7 +385,7 @@ err:
return ret;
}
static int bma250_chip_config(struct bma180_data *data)
static int bma25x_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
@ -367,8 +397,12 @@ static int bma250_chip_config(struct bma180_data *data)
ret = bma180_set_scale(data, 38344); /* 2 G */
if (ret)
goto err;
ret = bma180_set_bits(data, BMA250_INT_MAP_REG,
BMA250_INT1_DATA_MASK, 1);
/*
* 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);
if (ret)
goto err;
@ -394,7 +428,7 @@ err:
dev_err(&data->client->dev, "failed to disable the chip\n");
}
static void bma250_chip_disable(struct bma180_data *data)
static void bma25x_chip_disable(struct bma180_data *data)
{
if (bma180_set_new_data_intr_state(data, false))
goto err;
@ -497,7 +531,7 @@ static int bma180_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 48; /* 0 LSB @ 24 degree C */
*val = data->part_info->center_temp;
return IIO_VAL_INT;
default:
return -EINVAL;
@ -627,34 +661,96 @@ 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[] = {
[BMA180] = {
bma180_channels, ARRAY_SIZE(bma180_channels),
bma180_scale_table, ARRAY_SIZE(bma180_scale_table),
bma180_bw_table, ARRAY_SIZE(bma180_bw_table),
BMA180_CTRL_REG0, BMA180_RESET_INT,
BMA180_CTRL_REG0, BMA180_SLEEP,
BMA180_BW_TCS, BMA180_BW,
BMA180_OFFSET_LSB1, BMA180_RANGE,
BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER,
BMA180_CTRL_REG3, BMA180_NEW_DATA_INT,
BMA180_RESET,
bma180_chip_config,
bma180_chip_disable,
.chip_id = BMA180_ID_REG_VAL,
.channels = bma180_channels,
.num_channels = ARRAY_SIZE(bma180_channels),
.scale_table = bma180_scale_table,
.num_scales = ARRAY_SIZE(bma180_scale_table),
.bw_table = bma180_bw_table,
.num_bw = ARRAY_SIZE(bma180_bw_table),
.center_temp = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA180_CTRL_REG0,
.int_reset_mask = BMA180_RESET_INT,
.sleep_reg = BMA180_CTRL_REG0,
.sleep_mask = BMA180_SLEEP,
.bw_reg = BMA180_BW_TCS,
.bw_mask = BMA180_BW,
.scale_reg = BMA180_OFFSET_LSB1,
.scale_mask = BMA180_RANGE,
.power_reg = BMA180_TCO_Z,
.power_mask = BMA180_MODE_CONFIG,
.lowpower_val = BMA180_LOW_POWER,
.int_enable_reg = BMA180_CTRL_REG3,
.int_enable_mask = BMA180_NEW_DATA_INT,
.softreset_reg = BMA180_RESET,
.chip_config = bma180_chip_config,
.chip_disable = bma180_chip_disable,
},
[BMA250] = {
bma250_channels, ARRAY_SIZE(bma250_channels),
bma250_scale_table, ARRAY_SIZE(bma250_scale_table),
bma250_bw_table, ARRAY_SIZE(bma250_bw_table),
BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK,
BMA250_POWER_REG, BMA250_SUSPEND_MASK,
BMA250_BW_REG, BMA250_BW_MASK,
BMA250_RANGE_REG, BMA250_RANGE_MASK,
BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1,
BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK,
BMA250_RESET_REG,
bma250_chip_config,
bma250_chip_disable,
.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),
.center_temp = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA250_INT_RESET_REG,
.int_reset_mask = BMA250_INT_RESET_MASK,
.sleep_reg = BMA250_POWER_REG,
.sleep_mask = BMA250_SUSPEND_MASK,
.bw_reg = BMA250_BW_REG,
.bw_mask = BMA250_BW_MASK,
.scale_reg = BMA250_RANGE_REG,
.scale_mask = BMA250_RANGE_MASK,
.power_reg = BMA250_POWER_REG,
.power_mask = BMA250_LOWPOWER_MASK,
.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,
.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),
.center_temp = 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,
.chip_config = bma25x_chip_config,
.chip_disable = bma25x_chip_disable,
},
};
@ -712,12 +808,13 @@ static const struct iio_trigger_ops bma180_trigger_ops = {
static int bma180_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct bma180_data *data;
struct iio_dev *indio_dev;
enum chip_ids chip;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@ -725,22 +822,56 @@ static int bma180_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
data->client = client;
if (client->dev.of_node)
chip = (enum chip_ids)of_device_get_match_data(&client->dev);
chip = (enum chip_ids)of_device_get_match_data(dev);
else
chip = id->driver_data;
data->part_info = &bma180_part_info[chip];
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
ret = iio_read_mount_matrix(dev, "mount-matrix",
&data->orientation);
if (ret)
return ret;
data->vdd_supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(data->vdd_supply)) {
if (PTR_ERR(data->vdd_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vdd regulator %d\n",
(int)PTR_ERR(data->vdd_supply));
return PTR_ERR(data->vdd_supply);
}
data->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(data->vddio_supply)) {
if (PTR_ERR(data->vddio_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vddio regulator %d\n",
(int)PTR_ERR(data->vddio_supply));
return PTR_ERR(data->vddio_supply);
}
/* Typical voltage 2.4V these are min and max */
ret = regulator_set_voltage(data->vdd_supply, 1620000, 3600000);
if (ret)
return ret;
ret = regulator_set_voltage(data->vddio_supply, 1200000, 3600000);
if (ret)
return ret;
ret = regulator_enable(data->vdd_supply);
if (ret) {
dev_err(dev, "Failed to enable vdd regulator: %d\n", ret);
return ret;
}
ret = regulator_enable(data->vddio_supply);
if (ret) {
dev_err(dev, "Failed to enable vddio regulator: %d\n", ret);
goto err_disable_vdd;
}
/* Wait to make sure we started up properly (3 ms at least) */
usleep_range(3000, 5000);
ret = data->part_info->chip_config(data);
if (ret < 0)
goto err_chip_disable;
mutex_init(&data->mutex);
indio_dev->dev.parent = &client->dev;
indio_dev->dev.parent = dev;
indio_dev->channels = data->part_info->channels;
indio_dev->num_channels = data->part_info->num_channels;
indio_dev->name = id->name;
@ -755,15 +886,15 @@ static int bma180_probe(struct i2c_client *client,
goto err_chip_disable;
}
ret = devm_request_irq(&client->dev, client->irq,
ret = devm_request_irq(dev, client->irq,
iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING,
"bma180_event", data->trig);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
dev_err(dev, "unable to request IRQ\n");
goto err_trigger_free;
}
data->trig->dev.parent = &client->dev;
data->trig->dev.parent = dev;
data->trig->ops = &bma180_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
indio_dev->trig = iio_trigger_get(data->trig);
@ -776,13 +907,13 @@ static int bma180_probe(struct i2c_client *client,
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bma180_trigger_handler, NULL);
if (ret < 0) {
dev_err(&client->dev, "unable to setup iio triggered buffer\n");
dev_err(dev, "unable to setup iio triggered buffer\n");
goto err_trigger_unregister;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
dev_err(dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
@ -797,6 +928,9 @@ err_trigger_free:
iio_trigger_free(data->trig);
err_chip_disable:
data->part_info->chip_disable(data);
regulator_disable(data->vddio_supply);
err_disable_vdd:
regulator_disable(data->vdd_supply);
return ret;
}
@ -816,6 +950,8 @@ static int bma180_remove(struct i2c_client *client)
mutex_lock(&data->mutex);
data->part_info->chip_disable(data);
mutex_unlock(&data->mutex);
regulator_disable(data->vddio_supply);
regulator_disable(data->vdd_supply);
return 0;
}
@ -856,6 +992,7 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
static const struct i2c_device_id bma180_ids[] = {
{ "bma180", BMA180 },
{ "bma250", BMA250 },
{ "bma254", BMA254 },
{ }
};
@ -870,6 +1007,10 @@ static const struct of_device_id bma180_of_match[] = {
.compatible = "bosch,bma250",
.data = (void *)BMA250
},
{
.compatible = "bosch,bma254",
.data = (void *)BMA254
},
{ }
};
MODULE_DEVICE_TABLE(of, bma180_of_match);
@ -889,5 +1030,5 @@ module_i2c_driver(bma180_driver);
MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("Bosch BMA180/BMA250 triaxial acceleration sensor");
MODULE_DESCRIPTION("Bosch BMA180/BMA25x triaxial acceleration sensor");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,99 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register constants and other forward declarations needed by the bma400
* sources.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*/
#ifndef _BMA400_H_
#define _BMA400_H_
#include <linux/bits.h>
#include <linux/regmap.h>
/*
* Read-Only Registers
*/
/* Status and ID registers */
#define BMA400_CHIP_ID_REG 0x00
#define BMA400_ERR_REG 0x02
#define BMA400_STATUS_REG 0x03
/* Acceleration registers */
#define BMA400_X_AXIS_LSB_REG 0x04
#define BMA400_X_AXIS_MSB_REG 0x05
#define BMA400_Y_AXIS_LSB_REG 0x06
#define BMA400_Y_AXIS_MSB_REG 0x07
#define BMA400_Z_AXIS_LSB_REG 0x08
#define BMA400_Z_AXIS_MSB_REG 0x09
/* Sensor time registers */
#define BMA400_SENSOR_TIME0 0x0a
#define BMA400_SENSOR_TIME1 0x0b
#define BMA400_SENSOR_TIME2 0x0c
/* Event and interrupt registers */
#define BMA400_EVENT_REG 0x0d
#define BMA400_INT_STAT0_REG 0x0e
#define BMA400_INT_STAT1_REG 0x0f
#define BMA400_INT_STAT2_REG 0x10
/* Temperature register */
#define BMA400_TEMP_DATA_REG 0x11
/* FIFO length and data registers */
#define BMA400_FIFO_LENGTH0_REG 0x12
#define BMA400_FIFO_LENGTH1_REG 0x13
#define BMA400_FIFO_DATA_REG 0x14
/* Step count registers */
#define BMA400_STEP_CNT0_REG 0x15
#define BMA400_STEP_CNT1_REG 0x16
#define BMA400_STEP_CNT3_REG 0x17
#define BMA400_STEP_STAT_REG 0x18
/*
* Read-write configuration registers
*/
#define BMA400_ACC_CONFIG0_REG 0x19
#define BMA400_ACC_CONFIG1_REG 0x1a
#define BMA400_ACC_CONFIG2_REG 0x1b
#define BMA400_CMD_REG 0x7e
/* Chip ID of BMA 400 devices found in the chip ID register. */
#define BMA400_ID_REG_VAL 0x90
#define BMA400_LP_OSR_SHIFT 5
#define BMA400_NP_OSR_SHIFT 4
#define BMA400_SCALE_SHIFT 6
#define BMA400_TWO_BITS_MASK GENMASK(1, 0)
#define BMA400_LP_OSR_MASK GENMASK(6, 5)
#define BMA400_NP_OSR_MASK GENMASK(5, 4)
#define BMA400_ACC_ODR_MASK GENMASK(3, 0)
#define BMA400_ACC_SCALE_MASK GENMASK(7, 6)
#define BMA400_ACC_ODR_MIN_RAW 0x05
#define BMA400_ACC_ODR_LP_RAW 0x06
#define BMA400_ACC_ODR_MAX_RAW 0x0b
#define BMA400_ACC_ODR_MAX_HZ 800
#define BMA400_ACC_ODR_MIN_WHOLE_HZ 25
#define BMA400_ACC_ODR_MIN_HZ 12
#define BMA400_SCALE_MIN 38357
#define BMA400_SCALE_MAX 306864
#define BMA400_NUM_REGULATORS 2
#define BMA400_VDD_REGULATOR 0
#define BMA400_VDDIO_REGULATOR 1
extern const struct regmap_config bma400_regmap_config;
int bma400_probe(struct device *dev, struct regmap *regmap, const char *name);
int bma400_remove(struct device *dev);
#endif

View File

@ -0,0 +1,853 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Core IIO driver for Bosch BMA400 triaxial acceleration sensor.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*
* TODO:
* - Support for power management
* - Support events and interrupts
* - Create channel for step count
* - Create channel for sensor time
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "bma400.h"
/*
* The G-range selection may be one of 2g, 4g, 8, or 16g. The scale may
* be selected with the acc_range bits of the ACC_CONFIG1 register.
* NB: This buffer is populated in the device init.
*/
static int bma400_scales[8];
/*
* See the ACC_CONFIG1 section of the datasheet.
* NB: This buffer is populated in the device init.
*/
static int bma400_sample_freqs[14];
static const int bma400_osr_range[] = { 0, 1, 3 };
/* See the ACC_CONFIG0 section of the datasheet */
enum bma400_power_mode {
POWER_MODE_SLEEP = 0x00,
POWER_MODE_LOW = 0x01,
POWER_MODE_NORMAL = 0x02,
POWER_MODE_INVALID = 0x03,
};
struct bma400_sample_freq {
int hz;
int uhz;
};
struct bma400_data {
struct device *dev;
struct regmap *regmap;
struct regulator_bulk_data regulators[BMA400_NUM_REGULATORS];
struct mutex mutex; /* data register lock */
struct iio_mount_matrix orientation;
enum bma400_power_mode power_mode;
struct bma400_sample_freq sample_freq;
int oversampling_ratio;
int scale;
};
static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_CHIP_ID_REG:
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return false;
default:
return true;
}
}
static bool bma400_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return true;
default:
return false;
}
}
const struct regmap_config bma400_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BMA400_CMD_REG,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bma400_is_writable_reg,
.volatile_reg = bma400_is_volatile_reg,
};
EXPORT_SYMBOL(bma400_regmap_config);
static const struct iio_mount_matrix *
bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bma400_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma400_accel_get_mount_matrix),
{ }
};
#define BMA400_ACC_CHANNEL(_axis) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.ext_info = bma400_ext_info, \
}
static const struct iio_chan_spec bma400_channels[] = {
BMA400_ACC_CHANNEL(X),
BMA400_ACC_CHANNEL(Y),
BMA400_ACC_CHANNEL(Z),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
};
static int bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
{
unsigned int raw_temp;
int host_temp;
int ret;
if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &raw_temp);
if (ret)
return ret;
host_temp = sign_extend32(raw_temp, 7);
/*
* The formula for the TEMP_DATA register in the datasheet
* is: x * 0.5 + 23
*/
*val = (host_temp >> 1) + 23;
*val2 = (host_temp & 0x1) * 500000;
return IIO_VAL_INT_PLUS_MICRO;
}
static int bma400_get_accel_reg(struct bma400_data *data,
const struct iio_chan_spec *chan,
int *val)
{
__le16 raw_accel;
int lsb_reg;
int ret;
if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;
switch (chan->channel2) {
case IIO_MOD_X:
lsb_reg = BMA400_X_AXIS_LSB_REG;
break;
case IIO_MOD_Y:
lsb_reg = BMA400_Y_AXIS_LSB_REG;
break;
case IIO_MOD_Z:
lsb_reg = BMA400_Z_AXIS_LSB_REG;
break;
default:
dev_err(data->dev, "invalid axis channel modifier\n");
return -EINVAL;
}
/* bulk read two registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, lsb_reg, &raw_accel,
sizeof(raw_accel));
if (ret)
return ret;
*val = sign_extend32(le16_to_cpu(raw_accel), 11);
return IIO_VAL_INT;
}
static void bma400_output_data_rate_from_raw(int raw, unsigned int *val,
unsigned int *val2)
{
*val = BMA400_ACC_ODR_MAX_HZ >> (BMA400_ACC_ODR_MAX_RAW - raw);
if (raw > BMA400_ACC_ODR_MIN_RAW)
*val2 = 0;
else
*val2 = 500000;
}
static int bma400_get_accel_output_data_rate(struct bma400_data *data)
{
unsigned int val;
unsigned int odr;
int ret;
switch (data->power_mode) {
case POWER_MODE_LOW:
/*
* Runs at a fixed rate in low-power mode. See section 4.3
* in the datasheet.
*/
bma400_output_data_rate_from_raw(BMA400_ACC_ODR_LP_RAW,
&data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_NORMAL:
/*
* In normal mode the ODR can be found in the ACC_CONFIG1
* register.
*/
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
goto error;
odr = val & BMA400_ACC_ODR_MASK;
if (odr < BMA400_ACC_ODR_MIN_RAW ||
odr > BMA400_ACC_ODR_MAX_RAW) {
ret = -EINVAL;
goto error;
}
bma400_output_data_rate_from_raw(odr, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_SLEEP:
data->sample_freq.hz = 0;
data->sample_freq.uhz = 0;
return 0;
default:
ret = 0;
goto error;
}
error:
data->sample_freq.hz = -1;
data->sample_freq.uhz = -1;
return ret;
}
static int bma400_set_accel_output_data_rate(struct bma400_data *data,
int hz, int uhz)
{
unsigned int idx;
unsigned int odr;
unsigned int val;
int ret;
if (hz >= BMA400_ACC_ODR_MIN_WHOLE_HZ) {
if (uhz || hz > BMA400_ACC_ODR_MAX_HZ)
return -EINVAL;
/* Note this works because MIN_WHOLE_HZ is odd */
idx = __ffs(hz);
if (hz >> idx != BMA400_ACC_ODR_MIN_WHOLE_HZ)
return -EINVAL;
idx += BMA400_ACC_ODR_MIN_RAW + 1;
} else if (hz == BMA400_ACC_ODR_MIN_HZ && uhz == 500000) {
idx = BMA400_ACC_ODR_MIN_RAW;
} else {
return -EINVAL;
}
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;
/* preserve the range and normal mode osr */
odr = (~BMA400_ACC_ODR_MASK & val) | idx;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, odr);
if (ret)
return ret;
bma400_output_data_rate_from_raw(idx, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
}
static int bma400_get_accel_oversampling_ratio(struct bma400_data *data)
{
unsigned int val;
unsigned int osr;
int ret;
/*
* The oversampling ratio is stored in a different register
* based on the power-mode. In normal mode the OSR is stored
* in ACC_CONFIG1. In low-power mode it is stored in
* ACC_CONFIG0.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}
osr = (val & BMA400_LP_OSR_MASK) >> BMA400_LP_OSR_SHIFT;
data->oversampling_ratio = osr;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}
osr = (val & BMA400_NP_OSR_MASK) >> BMA400_NP_OSR_SHIFT;
data->oversampling_ratio = osr;
return 0;
case POWER_MODE_SLEEP:
data->oversampling_ratio = 0;
return 0;
default:
data->oversampling_ratio = -1;
return -EINVAL;
}
}
static int bma400_set_accel_oversampling_ratio(struct bma400_data *data,
int val)
{
unsigned int acc_config;
int ret;
if (val & ~BMA400_TWO_BITS_MASK)
return -EINVAL;
/*
* The oversampling ratio is stored in a different register
* based on the power-mode.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG,
&acc_config);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
(acc_config & ~BMA400_LP_OSR_MASK) |
(val << BMA400_LP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR\n");
return ret;
}
data->oversampling_ratio = val;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG,
&acc_config);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_NP_OSR_MASK) |
(val << BMA400_NP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR\n");
return ret;
}
data->oversampling_ratio = val;
return 0;
default:
return -EINVAL;
}
return ret;
}
static int bma400_accel_scale_to_raw(struct bma400_data *data,
unsigned int val)
{
int raw;
if (val == 0)
return -EINVAL;
/* Note this works because BMA400_SCALE_MIN is odd */
raw = __ffs(val);
if (val >> raw != BMA400_SCALE_MIN)
return -EINVAL;
return raw;
}
static int bma400_get_accel_scale(struct bma400_data *data)
{
unsigned int raw_scale;
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;
raw_scale = (val & BMA400_ACC_SCALE_MASK) >> BMA400_SCALE_SHIFT;
if (raw_scale > BMA400_TWO_BITS_MASK)
return -EINVAL;
data->scale = BMA400_SCALE_MIN << raw_scale;
return 0;
}
static int bma400_set_accel_scale(struct bma400_data *data, unsigned int val)
{
unsigned int acc_config;
int raw;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &acc_config);
if (ret)
return ret;
raw = bma400_accel_scale_to_raw(data, val);
if (raw < 0)
return raw;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_ACC_SCALE_MASK) |
(raw << BMA400_SCALE_SHIFT));
if (ret)
return ret;
data->scale = val;
return 0;
}
static int bma400_get_power_mode(struct bma400_data *data)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_STATUS_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read status register\n");
return ret;
}
data->power_mode = (val >> 1) & BMA400_TWO_BITS_MASK;
return 0;
}
static int bma400_set_power_mode(struct bma400_data *data,
enum bma400_power_mode mode)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret)
return ret;
if (data->power_mode == mode)
return 0;
if (mode == POWER_MODE_INVALID)
return -EINVAL;
/* Preserve the low-power oversample ratio etc */
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
mode | (val & ~BMA400_TWO_BITS_MASK));
if (ret) {
dev_err(data->dev, "Failed to write to power-mode\n");
return ret;
}
data->power_mode = mode;
/*
* Update our cached osr and odr based on the new
* power-mode.
*/
bma400_get_accel_output_data_rate(data);
bma400_get_accel_oversampling_ratio(data);
return 0;
}
static void bma400_init_tables(void)
{
int raw;
int i;
for (i = 0; i + 1 < ARRAY_SIZE(bma400_sample_freqs); i += 2) {
raw = (i / 2) + 5;
bma400_output_data_rate_from_raw(raw, &bma400_sample_freqs[i],
&bma400_sample_freqs[i + 1]);
}
for (i = 0; i + 1 < ARRAY_SIZE(bma400_scales); i += 2) {
raw = i / 2;
bma400_scales[i] = 0;
bma400_scales[i + 1] = BMA400_SCALE_MIN << raw;
}
}
static int bma400_init(struct bma400_data *data)
{
unsigned int val;
int ret;
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read chip id register\n");
goto out;
}
if (val != BMA400_ID_REG_VAL) {
dev_err(data->dev, "Chip ID mismatch\n");
ret = -ENODEV;
goto out;
}
data->regulators[BMA400_VDD_REGULATOR].supply = "vdd";
data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio";
ret = devm_regulator_bulk_get(data->dev,
ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(data->dev,
"Failed to get regulators: %d\n",
ret);
goto out;
}
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
dev_err(data->dev, "Failed to enable regulators: %d\n",
ret);
goto out;
}
ret = bma400_get_power_mode(data);
if (ret) {
dev_err(data->dev, "Failed to get the initial power-mode\n");
goto err_reg_disable;
}
if (data->power_mode != POWER_MODE_NORMAL) {
ret = bma400_set_power_mode(data, POWER_MODE_NORMAL);
if (ret) {
dev_err(data->dev, "Failed to wake up the device\n");
goto err_reg_disable;
}
/*
* TODO: The datasheet waits 1500us here in the example, but
* lists 2/ODR as the wakeup time.
*/
usleep_range(1500, 2000);
}
bma400_init_tables();
ret = bma400_get_accel_output_data_rate(data);
if (ret)
goto err_reg_disable;
ret = bma400_get_accel_oversampling_ratio(data);
if (ret)
goto err_reg_disable;
ret = bma400_get_accel_scale(data);
if (ret)
goto err_reg_disable;
/*
* Once the interrupt engine is supported we might use the
* data_src_reg, but for now ensure this is set to the
* variable ODR filter selectable by the sample frequency
* channel.
*/
return regmap_write(data->regmap, BMA400_ACC_CONFIG2_REG, 0x00);
err_reg_disable:
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
out:
return ret;
}
static int bma400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&data->mutex);
ret = bma400_get_temp_reg(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
ret = bma400_get_accel_reg(data, chan, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
case IIO_ACCEL:
if (data->sample_freq.hz < 0)
return -EINVAL;
*val = data->sample_freq.hz;
*val2 = data->sample_freq.uhz;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
/*
* Runs at a fixed sampling frequency. See Section 4.4
* of the datasheet.
*/
*val = 6;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->scale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
/*
* TODO: We could avoid this logic and returning -EINVAL here if
* we set both the low-power and normal mode OSR registers when
* we configure the device.
*/
if (data->oversampling_ratio < 0)
return -EINVAL;
*val = data->oversampling_ratio;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int bma400_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_MICRO;
*vals = bma400_scales;
*length = ARRAY_SIZE(bma400_scales);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*type = IIO_VAL_INT;
*vals = bma400_osr_range;
*length = ARRAY_SIZE(bma400_osr_range);
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_sample_freqs;
*length = ARRAY_SIZE(bma400_sample_freqs);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int bma400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
/*
* The sample frequency is readonly for the temperature
* register and a fixed value in low-power mode.
*/
if (chan->type != IIO_ACCEL)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_output_data_rate(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SCALE:
if (val != 0 ||
val2 < BMA400_SCALE_MIN || val2 > BMA400_SCALE_MAX)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_scale(data, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
mutex_lock(&data->mutex);
ret = bma400_set_accel_oversampling_ratio(data, val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static int bma400_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info bma400_info = {
.read_raw = bma400_read_raw,
.read_avail = bma400_read_avail,
.write_raw = bma400_write_raw,
.write_raw_get_fmt = bma400_write_raw_get_fmt,
};
int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
{
struct iio_dev *indio_dev;
struct bma400_data *data;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->regmap = regmap;
data->dev = dev;
ret = bma400_init(data);
if (ret)
return ret;
ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation);
if (ret)
return ret;
mutex_init(&data->mutex);
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &bma400_info;
indio_dev->channels = bma400_channels;
indio_dev->num_channels = ARRAY_SIZE(bma400_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
dev_set_drvdata(dev, indio_dev);
return iio_device_register(indio_dev);
}
EXPORT_SYMBOL(bma400_probe);
int bma400_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bma400_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = bma400_set_power_mode(data, POWER_MODE_SLEEP);
mutex_unlock(&data->mutex);
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
iio_device_unregister(indio_dev);
return ret;
}
EXPORT_SYMBOL(bma400_remove);
MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>");
MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor core");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C IIO driver for Bosch BMA400 triaxial acceleration sensor.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*
* I2C address is either 0x14 or 0x15 depending on SDO
*/
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "bma400.h"
static int bma400_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &bma400_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "failed to create regmap\n");
return PTR_ERR(regmap);
}
return bma400_probe(&client->dev, regmap, id->name);
}
static int bma400_i2c_remove(struct i2c_client *client)
{
return bma400_remove(&client->dev);
}
static const struct i2c_device_id bma400_i2c_ids[] = {
{ "bma400", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids);
static const struct of_device_id bma400_of_i2c_match[] = {
{ .compatible = "bosch,bma400" },
{ }
};
MODULE_DEVICE_TABLE(of, bma400_of_i2c_match);
static struct i2c_driver bma400_i2c_driver = {
.driver = {
.name = "bma400",
.of_match_table = bma400_of_i2c_match,
},
.probe = bma400_i2c_probe,
.remove = bma400_i2c_remove,
.id_table = bma400_i2c_ids,
};
module_i2c_driver(bma400_i2c_driver);
MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>");
MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (I2C)");
MODULE_LICENSE("GPL");

View File

@ -130,6 +130,7 @@ struct kxcjk1013_data {
struct i2c_client *client;
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
struct mutex mutex;
s16 buffer[8];
u8 odr_bits;
@ -983,6 +984,20 @@ static const struct iio_event_spec kxcjk1013_event = {
BIT(IIO_EV_INFO_PERIOD)
};
static const struct iio_mount_matrix *
kxcjk1013_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct kxcjk1013_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info kxcjk1013_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kxcjk1013_get_mount_matrix),
{ }
};
#define KXCJK1013_CHANNEL(_axis) { \
.type = IIO_ACCEL, \
.modified = 1, \
@ -999,6 +1014,7 @@ static const struct iio_event_spec kxcjk1013_event = {
.endianness = IIO_LE, \
}, \
.event_spec = &kxcjk1013_event, \
.ext_info = kxcjk1013_ext_info, \
.num_event_specs = 1 \
}
@ -1267,11 +1283,18 @@ static int kxcjk1013_probe(struct i2c_client *client,
data->client = client;
pdata = dev_get_platdata(&client->dev);
if (pdata)
if (pdata) {
data->active_high_intr = pdata->active_high_intr;
else
data->orientation = pdata->orientation;
} else {
data->active_high_intr = true; /* default polarity */
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
&data->orientation);
if (ret)
return ret;
}
if (id) {
data->chipset = (enum kx_chipset)(id->driver_data);
name = id->name;

View File

@ -64,7 +64,7 @@ enum st_accel_type {
* struct st_sensors_platform_data - default accel platform data
* @drdy_int_pin: default accel DRDY is available on INT1 pin.
*/
static const struct st_sensors_platform_data default_accel_pdata = {
static __maybe_unused const struct st_sensors_platform_data default_accel_pdata = {
.drdy_int_pin = 1,
};

View File

@ -18,7 +18,6 @@
#include <linux/iio/common/st_sensors_i2c.h>
#include "st_accel.h"
#ifdef CONFIG_OF
static const struct of_device_id st_accel_of_match[] = {
{
/* An older compatible */
@ -108,9 +107,6 @@ static const struct of_device_id st_accel_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
#else
#define st_accel_of_match NULL
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id st_accel_acpi_match[] = {
@ -119,8 +115,6 @@ static const struct acpi_device_id st_accel_acpi_match[] = {
{ },
};
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
#else
#define st_accel_acpi_match NULL
#endif
static const struct i2c_device_id st_accel_id_table[] = {
@ -195,7 +189,7 @@ static int st_accel_i2c_remove(struct i2c_client *client)
static struct i2c_driver st_accel_driver = {
.driver = {
.name = "st-accel-i2c",
.of_match_table = of_match_ptr(st_accel_of_match),
.of_match_table = st_accel_of_match,
.acpi_match_table = ACPI_PTR(st_accel_acpi_match),
},
.probe_new = st_accel_i2c_probe,

View File

@ -17,7 +17,6 @@
#include <linux/iio/common/st_sensors_spi.h>
#include "st_accel.h"
#ifdef CONFIG_OF
/*
* For new single-chip sensors use <device_name> as compatible string.
* For old single-chip devices keep <device_name>-accel to maintain
@ -96,9 +95,6 @@ static const struct of_device_id st_accel_of_match[] = {
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
#else
#define st_accel_of_match NULL
#endif
static int st_accel_spi_probe(struct spi_device *spi)
{
@ -107,8 +103,7 @@ static int st_accel_spi_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&spi->dev, st_accel_of_match,
spi->modalias, sizeof(spi->modalias));
st_sensors_dev_name_probe(&spi->dev, spi->modalias, sizeof(spi->modalias));
settings = st_accel_get_settings(spi->modalias);
if (!settings) {
@ -166,7 +161,7 @@ MODULE_DEVICE_TABLE(spi, st_accel_id_table);
static struct spi_driver st_accel_driver = {
.driver = {
.name = "st-accel-spi",
.of_match_table = of_match_ptr(st_accel_of_match),
.of_match_table = st_accel_of_match,
},
.probe = st_accel_spi_probe,
.remove = st_accel_spi_remove,

View File

@ -21,6 +21,13 @@ config AD_SIGMA_DELTA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7091R5
tristate "Analog Devices AD7091R5 ADC Driver"
depends on I2C
select REGMAP_I2C
help
Say yes here to build support for Analog Devices AD7091R-5 ADC.
config AD7124
tristate "Analog Devices AD7124 and similar sigma-delta ADCs driver"
depends on SPI_MASTER
@ -523,6 +530,16 @@ config LTC2485
To compile this driver as a module, choose M here: the module will be
called ltc2485.
config LTC2496
tristate "Linear Technology LTC2496 ADC driver"
depends on SPI
help
Say yes here to build support for Linear Technology LTC2496
16-Bit 8-/16-Channel Delta Sigma ADC.
To compile this driver as a module, choose M here: the module will be
called ltc2496.
config LTC2497
tristate "Linear Technology LTC2497 ADC driver"
depends on I2C

View File

@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.o
@ -50,7 +51,8 @@ obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2497) += ltc2497.o
obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o
obj-$(CONFIG_LTC2497) += ltc2497.o ltc2497-core.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1118) += max1118.o

View File

@ -0,0 +1,298 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AD7091RX Analog to Digital converter driver
*
* Copyright 2014-2019 Analog Devices Inc.
*/
#include <linux/bitops.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "ad7091r-base.h"
#define AD7091R_REG_RESULT 0
#define AD7091R_REG_CHANNEL 1
#define AD7091R_REG_CONF 2
#define AD7091R_REG_ALERT 3
#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4)
#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5)
#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6)
/* AD7091R_REG_RESULT */
#define AD7091R_REG_RESULT_CH_ID(x) (((x) >> 13) & 0x3)
#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff)
/* AD7091R_REG_CONF */
#define AD7091R_REG_CONF_AUTO BIT(8)
#define AD7091R_REG_CONF_CMD BIT(10)
#define AD7091R_REG_CONF_MODE_MASK \
(AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD)
enum ad7091r_mode {
AD7091R_MODE_SAMPLE,
AD7091R_MODE_COMMAND,
AD7091R_MODE_AUTOCYCLE,
};
struct ad7091r_state {
struct device *dev;
struct regmap *map;
struct regulator *vref;
const struct ad7091r_chip_info *chip_info;
enum ad7091r_mode mode;
struct mutex lock; /*lock to prevent concurent reads */
};
static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
{
int ret, conf;
switch (mode) {
case AD7091R_MODE_SAMPLE:
conf = 0;
break;
case AD7091R_MODE_COMMAND:
conf = AD7091R_REG_CONF_CMD;
break;
case AD7091R_MODE_AUTOCYCLE:
conf = AD7091R_REG_CONF_AUTO;
break;
default:
return -EINVAL;
}
ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
AD7091R_REG_CONF_MODE_MASK, conf);
if (ret)
return ret;
st->mode = mode;
return 0;
}
static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel)
{
unsigned int dummy;
int ret;
/* AD7091R_REG_CHANNEL specified which channels to be converted */
ret = regmap_write(st->map, AD7091R_REG_CHANNEL,
BIT(channel) | (BIT(channel) << 8));
if (ret)
return ret;
/*
* There is a latency of one conversion before the channel conversion
* sequence is updated
*/
return regmap_read(st->map, AD7091R_REG_RESULT, &dummy);
}
static int ad7091r_read_one(struct iio_dev *iio_dev,
unsigned int channel, unsigned int *read_val)
{
struct ad7091r_state *st = iio_priv(iio_dev);
unsigned int val;
int ret;
ret = ad7091r_set_channel(st, channel);
if (ret)
return ret;
ret = regmap_read(st->map, AD7091R_REG_RESULT, &val);
if (ret)
return ret;
if (AD7091R_REG_RESULT_CH_ID(val) != channel)
return -EIO;
*read_val = AD7091R_REG_RESULT_CONV_RESULT(val);
return 0;
}
static int ad7091r_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
{
struct ad7091r_state *st = iio_priv(iio_dev);
unsigned int read_val;
int ret;
mutex_lock(&st->lock);
switch (m) {
case IIO_CHAN_INFO_RAW:
if (st->mode != AD7091R_MODE_COMMAND) {
ret = -EBUSY;
goto unlock;
}
ret = ad7091r_read_one(iio_dev, chan->channel, &read_val);
if (ret)
goto unlock;
*val = read_val;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
if (st->vref) {
ret = regulator_get_voltage(st->vref);
if (ret < 0)
goto unlock;
*val = ret / 1000;
} else {
*val = st->chip_info->vref_mV;
}
*val2 = chan->scan_type.realbits;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
ret = -EINVAL;
break;
}
unlock:
mutex_unlock(&st->lock);
return ret;
}
static const struct iio_info ad7091r_info = {
.read_raw = ad7091r_read_raw,
};
static irqreturn_t ad7091r_event_handler(int irq, void *private)
{
struct ad7091r_state *st = (struct ad7091r_state *) private;
struct iio_dev *iio_dev = dev_get_drvdata(st->dev);
unsigned int i, read_val;
int ret;
s64 timestamp = iio_get_time_ns(iio_dev);
ret = regmap_read(st->map, AD7091R_REG_ALERT, &read_val);
if (ret)
return IRQ_HANDLED;
for (i = 0; i < st->chip_info->num_channels; i++) {
if (read_val & BIT(i * 2))
iio_push_event(iio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING), timestamp);
if (read_val & BIT(i * 2 + 1))
iio_push_event(iio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING), timestamp);
}
return IRQ_HANDLED;
}
static void ad7091r_remove(void *data)
{
struct ad7091r_state *st = data;
regulator_disable(st->vref);
}
int ad7091r_probe(struct device *dev, const char *name,
const struct ad7091r_chip_info *chip_info,
struct regmap *map, int irq)
{
struct iio_dev *iio_dev;
struct ad7091r_state *st;
int ret;
iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!iio_dev)
return -ENOMEM;
st = iio_priv(iio_dev);
st->dev = dev;
st->chip_info = chip_info;
st->map = map;
iio_dev->dev.parent = dev;
iio_dev->name = name;
iio_dev->info = &ad7091r_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->num_channels = chip_info->num_channels;
iio_dev->channels = chip_info->channels;
if (irq) {
ret = devm_request_threaded_irq(dev, irq, NULL,
ad7091r_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, name, st);
if (ret)
return ret;
}
st->vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(st->vref)) {
if (PTR_ERR(st->vref) == -EPROBE_DEFER)
return -EPROBE_DEFER;
st->vref = NULL;
} else {
ret = regulator_enable(st->vref);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ad7091r_remove, st);
if (ret)
return ret;
}
/* Use command mode by default to convert only desired channels*/
ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND);
if (ret)
return ret;
return devm_iio_device_register(dev, iio_dev);
}
EXPORT_SYMBOL_GPL(ad7091r_probe);
static bool ad7091r_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AD7091R_REG_RESULT:
case AD7091R_REG_ALERT:
return false;
default:
return true;
}
}
static bool ad7091r_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AD7091R_REG_RESULT:
case AD7091R_REG_ALERT:
return true;
default:
return false;
}
}
const struct regmap_config ad7091r_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.writeable_reg = ad7091r_writeable_reg,
.volatile_reg = ad7091r_volatile_reg,
};
EXPORT_SYMBOL_GPL(ad7091r_regmap_config);
MODULE_AUTHOR("Beniamin Bia <beniamin.bia@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7091Rx multi-channel converters");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AD7091RX Analog to Digital converter driver
*
* Copyright 2014-2019 Analog Devices Inc.
*/
#ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__
#define __DRIVERS_IIO_ADC_AD7091R_BASE_H__
struct device;
struct ad7091r_state;
struct ad7091r_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
unsigned int vref_mV;
};
extern const struct regmap_config ad7091r_regmap_config;
int ad7091r_probe(struct device *dev, const char *name,
const struct ad7091r_chip_info *chip_info,
struct regmap *map, int irq);
#endif /* __DRIVERS_IIO_ADC_AD7091R_BASE_H__ */

View File

@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AD7091R5 Analog to Digital converter driver
*
* Copyright 2014-2019 Analog Devices Inc.
*/
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "ad7091r-base.h"
static const struct iio_event_spec ad7091r5_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
.channel = idx, \
.event_spec = ev, \
.num_event_specs = num_ev, \
.scan_type.storagebits = 16, \
.scan_type.realbits = bits, \
}
static const struct iio_chan_spec ad7091r5_channels_irq[] = {
AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
AD7091R_CHANNEL(1, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
AD7091R_CHANNEL(2, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
AD7091R_CHANNEL(3, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
};
static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
AD7091R_CHANNEL(0, 12, NULL, 0),
AD7091R_CHANNEL(1, 12, NULL, 0),
AD7091R_CHANNEL(2, 12, NULL, 0),
AD7091R_CHANNEL(3, 12, NULL, 0),
};
static const struct ad7091r_chip_info ad7091r5_chip_info_irq = {
.channels = ad7091r5_channels_irq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_irq),
.vref_mV = 2500,
};
static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
.channels = ad7091r5_channels_noirq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_noirq),
.vref_mV = 2500,
};
static int ad7091r5_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
const struct ad7091r_chip_info *chip_info;
struct regmap *map = devm_regmap_init_i2c(i2c, &ad7091r_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
if (i2c->irq)
chip_info = &ad7091r5_chip_info_irq;
else
chip_info = &ad7091r5_chip_info_noirq;
return ad7091r_probe(&i2c->dev, id->name, chip_info, map, i2c->irq);
}
static const struct of_device_id ad7091r5_dt_ids[] = {
{ .compatible = "adi,ad7091r5" },
{},
};
MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids);
static const struct i2c_device_id ad7091r5_i2c_ids[] = {
{"ad7091r5", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids);
static struct i2c_driver ad7091r5_driver = {
.driver = {
.name = "ad7091r5",
.of_match_table = ad7091r5_dt_ids,
},
.probe = ad7091r5_i2c_probe,
.id_table = ad7091r5_i2c_ids,
};
module_i2c_driver(ad7091r5_driver);
MODULE_AUTHOR("Beniamin Bia <beniamin.bia@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7091R5 multi-channel ADC driver");
MODULE_LICENSE("GPL v2");

View File

@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
@ -224,6 +225,7 @@ static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
.addr_shift = 0,
.read_mask = BIT(6),
.data_reg = AD7124_DATA,
.irq_flags = IRQF_TRIGGER_FALLING,
};
static int ad7124_set_channel_odr(struct ad7124_state *st,

View File

@ -11,7 +11,7 @@
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@ -34,7 +34,7 @@ struct ad7266_state {
enum ad7266_range range;
enum ad7266_mode mode;
bool fixed_addr;
struct gpio gpios[3];
struct gpio_desc *gpios[3];
/*
* DMA (thus cache coherency maintenance) requires the
@ -117,7 +117,7 @@ static void ad7266_select_input(struct ad7266_state *st, unsigned int nr)
}
for (i = 0; i < 3; ++i)
gpio_set_value(st->gpios[i].gpio, (bool)(nr & BIT(i)));
gpiod_set_value(st->gpios[i], (bool)(nr & BIT(i)));
}
static int ad7266_update_scan_mode(struct iio_dev *indio_dev,
@ -376,7 +376,7 @@ static void ad7266_init_channels(struct iio_dev *indio_dev)
}
static const char * const ad7266_gpio_labels[] = {
"AD0", "AD1", "AD2",
"ad0", "ad1", "ad2",
};
static int ad7266_probe(struct spi_device *spi)
@ -419,14 +419,14 @@ static int ad7266_probe(struct spi_device *spi)
if (!st->fixed_addr) {
for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) {
st->gpios[i].gpio = pdata->addr_gpios[i];
st->gpios[i].flags = GPIOF_OUT_INIT_LOW;
st->gpios[i].label = ad7266_gpio_labels[i];
st->gpios[i] = devm_gpiod_get(&spi->dev,
ad7266_gpio_labels[i],
GPIOD_OUT_LOW);
if (IS_ERR(st->gpios[i])) {
ret = PTR_ERR(st->gpios[i]);
goto error_disable_reg;
}
}
ret = gpio_request_array(st->gpios,
ARRAY_SIZE(st->gpios));
if (ret)
goto error_disable_reg;
}
} else {
st->fixed_addr = true;
@ -465,7 +465,7 @@ static int ad7266_probe(struct spi_device *spi)
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad7266_trigger_handler, &iio_triggered_buffer_setup_ops);
if (ret)
goto error_free_gpios;
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
@ -475,9 +475,6 @@ static int ad7266_probe(struct spi_device *spi)
error_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
error_free_gpios:
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
@ -492,8 +489,6 @@ static int ad7266_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
if (!IS_ERR(st->reg))
regulator_disable(st->reg);

View File

@ -203,6 +203,7 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
.set_mode = ad7780_set_mode,
.postprocess_sample = ad7780_postprocess_sample,
.has_registers = false,
.irq_flags = IRQF_TRIGGER_LOW,
};
#define AD7780_CHANNEL(bits, wordsize) \

View File

@ -205,6 +205,7 @@ static const struct ad_sigma_delta_info ad7791_sigma_delta_info = {
.has_registers = true,
.addr_shift = 4,
.read_mask = BIT(3),
.irq_flags = IRQF_TRIGGER_LOW,
};
static int ad7791_read_raw(struct iio_dev *indio_dev,

View File

@ -206,6 +206,7 @@ static const struct ad_sigma_delta_info ad7793_sigma_delta_info = {
.has_registers = true,
.addr_shift = 3,
.read_mask = BIT(6),
.irq_flags = IRQF_TRIGGER_LOW,
};
static const struct ad_sd_calib_data ad7793_calib_arr[6] = {

View File

@ -43,11 +43,17 @@ enum ad7887_channels {
/**
* struct ad7887_chip_info - chip specifc information
* @int_vref_mv: the internal reference voltage
* @channel: channel specification
* @channels: channels specification
* @num_channels: number of channels
* @dual_channels: channels specification in dual mode
* @num_dual_channels: number of channels in dual mode
*/
struct ad7887_chip_info {
u16 int_vref_mv;
struct iio_chan_spec channel[3];
const struct iio_chan_spec *channels;
unsigned int num_channels;
const struct iio_chan_spec *dual_channels;
unsigned int num_dual_channels;
};
struct ad7887_state {
@ -183,45 +189,43 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
#define AD7887_CHANNEL(x) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (x), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (x), \
.scan_index = (x), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.shift = 0, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec ad7887_channels[] = {
AD7887_CHANNEL(0),
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static const struct iio_chan_spec ad7887_dual_channels[] = {
AD7887_CHANNEL(0),
AD7887_CHANNEL(1),
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
/*
* More devices added in future
*/
[ID_AD7887] = {
.channel[0] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 1,
.scan_index = 1,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.channel[1] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 0,
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2),
.channels = ad7887_channels,
.num_channels = ARRAY_SIZE(ad7887_channels),
.dual_channels = ad7887_dual_channels,
.num_dual_channels = ARRAY_SIZE(ad7887_dual_channels),
.int_vref_mv = 2500,
},
};
@ -306,11 +310,11 @@ static int ad7887_probe(struct spi_device *spi)
spi_message_init(&st->msg[AD7887_CH1]);
spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]);
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = 3;
indio_dev->channels = st->chip_info->dual_channels;
indio_dev->num_channels = st->chip_info->num_dual_channels;
} else {
indio_dev->channels = &st->chip_info->channel[1];
indio_dev->num_channels = 2;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* AD7904/AD7914/AD7923/AD7924 SPI ADC driver
* AD7904/AD7914/AD7923/AD7924/AD7908/AD7918/AD7928 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
@ -29,15 +29,10 @@
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */
#define AD7923_CHANNEL_0 (0) /* analog input 0 */
#define AD7923_CHANNEL_1 (1) /* analog input 1 */
#define AD7923_CHANNEL_2 (2) /* analog input 2 */
#define AD7923_CHANNEL_3 (3) /* analog input 3 */
#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
#define AD7923_MAX_CHAN 4
#define AD7923_PM_MODE_WRITE(mode) ((mode) << 4) /* write mode */
#define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */
@ -78,6 +73,9 @@ enum ad7923_id {
AD7904,
AD7914,
AD7924,
AD7908,
AD7918,
AD7928
};
#define AD7923_V_CHAN(index, bits) \
@ -106,9 +104,25 @@ const struct iio_chan_spec name ## _channels[] = { \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DECLARE_AD7908_CHANNELS(name, bits) \
const struct iio_chan_spec name ## _channels[] = { \
AD7923_V_CHAN(0, bits), \
AD7923_V_CHAN(1, bits), \
AD7923_V_CHAN(2, bits), \
AD7923_V_CHAN(3, bits), \
AD7923_V_CHAN(4, bits), \
AD7923_V_CHAN(5, bits), \
AD7923_V_CHAN(6, bits), \
AD7923_V_CHAN(7, bits), \
IIO_CHAN_SOFT_TIMESTAMP(8), \
}
static DECLARE_AD7923_CHANNELS(ad7904, 8);
static DECLARE_AD7923_CHANNELS(ad7914, 10);
static DECLARE_AD7923_CHANNELS(ad7924, 12);
static DECLARE_AD7908_CHANNELS(ad7908, 8);
static DECLARE_AD7908_CHANNELS(ad7918, 10);
static DECLARE_AD7908_CHANNELS(ad7928, 12);
static const struct ad7923_chip_info ad7923_chip_info[] = {
[AD7904] = {
@ -123,6 +137,18 @@ static const struct ad7923_chip_info ad7923_chip_info[] = {
.channels = ad7924_channels,
.num_channels = ARRAY_SIZE(ad7924_channels),
},
[AD7908] = {
.channels = ad7908_channels,
.num_channels = ARRAY_SIZE(ad7908_channels),
},
[AD7918] = {
.channels = ad7918_channels,
.num_channels = ARRAY_SIZE(ad7918_channels),
},
[AD7928] = {
.channels = ad7928_channels,
.num_channels = ARRAY_SIZE(ad7928_channels),
},
};
/**
@ -135,7 +161,11 @@ static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
int i, cmd, len;
len = 0;
for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) {
/*
* For this driver the last channel is always the software timestamp so
* skip that one.
*/
for_each_set_bit(i, active_scan_mask, indio_dev->num_channels - 1) {
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
@ -188,7 +218,7 @@ done:
return IRQ_HANDLED;
}
static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch)
static int ad7923_scan_direct(struct ad7923_state *st, unsigned int ch)
{
int ret, cmd;
@ -348,13 +378,29 @@ static const struct spi_device_id ad7923_id[] = {
{"ad7914", AD7914},
{"ad7923", AD7924},
{"ad7924", AD7924},
{"ad7908", AD7908},
{"ad7918", AD7918},
{"ad7928", AD7928},
{}
};
MODULE_DEVICE_TABLE(spi, ad7923_id);
static const struct of_device_id ad7923_of_match[] = {
{ .compatible = "adi,ad7904", },
{ .compatible = "adi,ad7914", },
{ .compatible = "adi,ad7923", },
{ .compatible = "adi,ad7924", },
{ .compatible = "adi,ad7908", },
{ .compatible = "adi,ad7918", },
{ .compatible = "adi,ad7928", },
{ },
};
MODULE_DEVICE_TABLE(of, ad7923_of_match);
static struct spi_driver ad7923_driver = {
.driver = {
.name = "ad7923",
.of_match_table = ad7923_of_match,
},
.probe = ad7923_probe,
.remove = ad7923_remove,
@ -364,5 +410,5 @@ module_spi_driver(ad7923_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_DESCRIPTION("Analog Devices AD7923 and similar ADC");
MODULE_LICENSE("GPL v2");

View File

@ -167,6 +167,21 @@ static int ad799x_read_config(struct ad799x_state *st)
}
}
static int ad799x_update_config(struct ad799x_state *st, u16 config)
{
int ret;
ret = ad799x_write_config(st, config);
if (ret < 0)
return ret;
ret = ad799x_read_config(st);
if (ret < 0)
return ret;
st->config = ret;
return 0;
}
/**
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
*
@ -808,13 +823,9 @@ static int ad799x_probe(struct i2c_client *client,
indio_dev->channels = st->chip_config->channel;
indio_dev->num_channels = chip_info->num_channels;
ret = ad799x_write_config(st, st->chip_config->default_config);
if (ret < 0)
ret = ad799x_update_config(st, st->chip_config->default_config);
if (ret)
goto error_disable_vref;
ret = ad799x_read_config(st);
if (ret < 0)
goto error_disable_vref;
st->config = ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad799x_trigger_handler, NULL);
@ -864,6 +875,48 @@ static int ad799x_remove(struct i2c_client *client)
return 0;
}
static int __maybe_unused ad799x_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ad799x_state *st = iio_priv(indio_dev);
regulator_disable(st->vref);
regulator_disable(st->reg);
return 0;
}
static int __maybe_unused ad799x_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
ret = regulator_enable(st->reg);
if (ret) {
dev_err(dev, "Unable to enable vcc regulator\n");
return ret;
}
ret = regulator_enable(st->vref);
if (ret) {
regulator_disable(st->reg);
dev_err(dev, "Unable to enable vref regulator\n");
return ret;
}
/* resync config */
ret = ad799x_update_config(st, st->config);
if (ret) {
regulator_disable(st->vref);
regulator_disable(st->reg);
return ret;
}
return 0;
}
static SIMPLE_DEV_PM_OPS(ad799x_pm_ops, ad799x_suspend, ad799x_resume);
static const struct i2c_device_id ad799x_id[] = {
{ "ad7991", ad7991 },
{ "ad7995", ad7995 },
@ -881,6 +934,7 @@ MODULE_DEVICE_TABLE(i2c, ad799x_id);
static struct i2c_driver ad799x_driver = {
.driver = {
.name = "ad799x",
.pm = &ad799x_pm_ops,
},
.probe = ad799x_probe,
.remove = ad799x_remove,

View File

@ -500,7 +500,7 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
ret = request_irq(sigma_delta->spi->irq,
ad_sd_data_rdy_trig_poll,
IRQF_TRIGGER_LOW,
sigma_delta->info->irq_flags,
indio_dev->name,
sigma_delta);
if (ret)

View File

@ -1444,10 +1444,10 @@ static void at91_adc_dma_init(struct platform_device *pdev)
if (st->dma_st.dma_chan)
return;
st->dma_st.dma_chan = dma_request_slave_channel(&pdev->dev, "rx");
if (!st->dma_st.dma_chan) {
st->dma_st.dma_chan = dma_request_chan(&pdev->dev, "rx");
if (IS_ERR(st->dma_st.dma_chan)) {
dev_info(&pdev->dev, "can't get DMA channel\n");
st->dma_st.dma_chan = NULL;
goto dma_exit;
}

View File

@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ltc2496.c - Driver for Analog Devices/Linear Technology LTC2496 ADC
*
* Based on ltc2497.c which has
* Copyright (C) 2017 Analog Devices Inc.
*
* Licensed under the GPL-2.
*
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2496fc.pdf
*/
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include "ltc2497.h"
struct ltc2496_driverdata {
/* this must be the first member */
struct ltc2497core_driverdata common_ddata;
struct spi_device *spi;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned char rxbuf[3] ____cacheline_aligned;
unsigned char txbuf[3];
};
static int ltc2496_result_and_measure(struct ltc2497core_driverdata *ddata,
u8 address, int *val)
{
struct ltc2496_driverdata *st =
container_of(ddata, struct ltc2496_driverdata, common_ddata);
struct spi_transfer t = {
.tx_buf = st->txbuf,
.rx_buf = st->rxbuf,
.len = sizeof(st->txbuf),
};
int ret;
st->txbuf[0] = LTC2497_ENABLE | address;
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret < 0) {
dev_err(&st->spi->dev, "spi_sync_transfer failed: %pe\n",
ERR_PTR(ret));
return ret;
}
if (val)
*val = ((st->rxbuf[0] & 0x3f) << 12 |
st->rxbuf[1] << 4 | st->rxbuf[2] >> 4) -
(1 << 17);
return 0;
}
static int ltc2496_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ltc2496_driverdata *st;
struct device *dev = &spi->dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->common_ddata.result_and_measure = ltc2496_result_and_measure;
return ltc2497core_probe(dev, indio_dev);
}
static int ltc2496_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
ltc2497core_remove(indio_dev);
return 0;
}
static const struct of_device_id ltc2496_of_match[] = {
{ .compatible = "lltc,ltc2496", },
{},
};
MODULE_DEVICE_TABLE(of, ltc2496_of_match);
static struct spi_driver ltc2496_driver = {
.driver = {
.name = "ltc2496",
.of_match_table = of_match_ptr(ltc2496_of_match),
},
.probe = ltc2496_probe,
.remove = ltc2496_remove,
};
module_spi_driver(ltc2496_driver);
MODULE_AUTHOR("Uwe Kleine-König <u.kleine-könig@pengutronix.de>");
MODULE_DESCRIPTION("Linear Technology LTC2496 ADC driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,243 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ltc2497-core.c - Common code for Analog Devices/Linear Technology
* LTC2496 and LTC2497 ADCs
*
* Copyright (C) 2017 Analog Devices Inc.
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include "ltc2497.h"
#define LTC2497_SGL BIT(4)
#define LTC2497_DIFF 0
#define LTC2497_SIGN BIT(3)
static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata)
{
s64 time_elapsed;
time_elapsed = ktime_ms_delta(ktime_get(), ddata->time_prev);
if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
/* delay if conversion time not passed
* since last read or write
*/
if (msleep_interruptible(
LTC2497_CONVERSION_TIME_MS - time_elapsed))
return -ERESTARTSYS;
return 0;
}
if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
/* We're in automatic mode -
* so the last reading is still not outdated
*/
return 0;
}
return 1;
}
static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, int *val)
{
int ret;
ret = ltc2497core_wait_conv(ddata);
if (ret < 0)
return ret;
if (ret || ddata->addr_prev != address) {
ret = ddata->result_and_measure(ddata, address, NULL);
if (ret < 0)
return ret;
ddata->addr_prev = address;
if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
return -ERESTARTSYS;
}
ret = ddata->result_and_measure(ddata, address, val);
if (ret < 0)
return ret;
ddata->time_prev = ktime_get();
return ret;
}
static int ltc2497core_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ltc2497core_read(ddata, chan->address, val);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(ddata->ref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = 17;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = (_ds_name), \
}
#define LTC2497_CHAN_DIFF(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
.address = (_addr | _chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.differential = 1, \
}
static const struct iio_chan_spec ltc2497core_channel[] = {
LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
};
static const struct iio_info ltc2497core_info = {
.read_raw = ltc2497core_read_raw,
};
int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
{
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
int ret;
indio_dev->dev.parent = dev;
indio_dev->name = dev_name(dev);
indio_dev->info = &ltc2497core_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ltc2497core_channel;
indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);
if (ret < 0)
return ret;
ddata->ref = devm_regulator_get(dev, "vref");
if (IS_ERR(ddata->ref)) {
if (PTR_ERR(ddata->ref) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vref regulator: %pe\n",
ddata->ref);
return PTR_ERR(ddata->ref);
}
ret = regulator_enable(ddata->ref);
if (ret < 0) {
dev_err(dev, "Failed to enable vref regulator: %pe\n",
ERR_PTR(ret));
return ret;
}
if (dev->platform_data) {
struct iio_map *plat_data;
plat_data = (struct iio_map *)dev->platform_data;
ret = iio_map_array_register(indio_dev, plat_data);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
goto err_regulator_disable;
}
}
ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
ddata->time_prev = ktime_get();
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_array_unregister;
return 0;
err_array_unregister:
iio_map_array_unregister(indio_dev);
err_regulator_disable:
regulator_disable(ddata->ref);
return ret;
}
EXPORT_SYMBOL_NS(ltc2497core_probe, LTC2497);
void ltc2497core_remove(struct iio_dev *indio_dev)
{
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
regulator_disable(ddata->ref);
}
EXPORT_SYMBOL_NS(ltc2497core_remove, LTC2497);
MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers");
MODULE_LICENSE("GPL v2");

View File

@ -7,27 +7,18 @@
* Datasheet: http://cds.linear.com/docs/en/datasheet/2497fd.pdf
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#define LTC2497_ENABLE 0xA0
#define LTC2497_SGL BIT(4)
#define LTC2497_DIFF 0
#define LTC2497_SIGN BIT(3)
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
#define LTC2497_CONVERSION_TIME_MS 150ULL
#include "ltc2497.h"
struct ltc2497_st {
struct ltc2497_driverdata {
/* this must be the first member */
struct ltc2497core_driverdata common_ddata;
struct i2c_client *client;
struct regulator *ref;
ktime_t time_prev;
u8 addr_prev;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@ -35,232 +26,59 @@ struct ltc2497_st {
__be32 buf ____cacheline_aligned;
};
static int ltc2497_wait_conv(struct ltc2497_st *st)
static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
u8 address, int *val)
{
s64 time_elapsed;
time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
/* delay if conversion time not passed
* since last read or write
*/
if (msleep_interruptible(
LTC2497_CONVERSION_TIME_MS - time_elapsed))
return -ERESTARTSYS;
return 0;
}
if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
/* We're in automatic mode -
* so the last reading is stil not outdated
*/
return 0;
}
return 1;
}
static int ltc2497_read(struct ltc2497_st *st, u8 address, int *val)
{
struct i2c_client *client = st->client;
struct ltc2497_driverdata *st =
container_of(ddata, struct ltc2497_driverdata, common_ddata);
int ret;
ret = ltc2497_wait_conv(st);
if (ret < 0)
return ret;
if (ret || st->addr_prev != address) {
ret = i2c_smbus_write_byte(st->client,
LTC2497_ENABLE | address);
if (ret < 0)
if (val) {
ret = i2c_master_recv(st->client, (char *)&st->buf, 3);
if (ret < 0) {
dev_err(&st->client->dev, "i2c_master_recv failed\n");
return ret;
st->addr_prev = address;
if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
return -ERESTARTSYS;
}
ret = i2c_master_recv(client, (char *)&st->buf, 3);
if (ret < 0) {
dev_err(&client->dev, "i2c_master_recv failed\n");
return ret;
}
st->time_prev = ktime_get();
}
/* convert and shift the result,
* and finally convert from offset binary to signed integer
*/
*val = (be32_to_cpu(st->buf) >> 14) - (1 << 17);
*val = (be32_to_cpu(st->buf) >> 14) - (1 << 17);
}
ret = i2c_smbus_write_byte(st->client,
LTC2497_ENABLE | address);
if (ret)
dev_err(&st->client->dev, "i2c transfer failed: %pe\n",
ERR_PTR(ret));
return ret;
}
static int ltc2497_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ltc2497_st *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ltc2497_read(st, chan->address, val);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(st->ref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = 17;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = (_ds_name), \
}
#define LTC2497_CHAN_DIFF(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
.address = (_addr | _chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.differential = 1, \
}
static const struct iio_chan_spec ltc2497_channel[] = {
LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
};
static const struct iio_info ltc2497_info = {
.read_raw = ltc2497_read_raw,
};
static int ltc2497_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct ltc2497_st *st;
struct iio_map *plat_data;
int ret;
struct ltc2497_driverdata *st;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_WRITE_BYTE))
return -EOPNOTSUPP;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
st->client = client;
st->common_ddata.result_and_measure = ltc2497_result_and_measure;
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->info = &ltc2497_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ltc2497_channel;
indio_dev->num_channels = ARRAY_SIZE(ltc2497_channel);
st->ref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(st->ref))
return PTR_ERR(st->ref);
ret = regulator_enable(st->ref);
if (ret < 0)
return ret;
if (client->dev.platform_data) {
plat_data = ((struct iio_map *)client->dev.platform_data);
ret = iio_map_array_register(indio_dev, plat_data);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
goto err_regulator_disable;
}
}
ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
if (ret < 0)
goto err_array_unregister;
st->addr_prev = LTC2497_CONFIG_DEFAULT;
st->time_prev = ktime_get();
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_array_unregister;
return 0;
err_array_unregister:
iio_map_array_unregister(indio_dev);
err_regulator_disable:
regulator_disable(st->ref);
return ret;
return ltc2497core_probe(dev, indio_dev);
}
static int ltc2497_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ltc2497_st *st = iio_priv(indio_dev);
iio_map_array_unregister(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(st->ref);
ltc2497core_remove(indio_dev);
return 0;
}

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#define LTC2497_ENABLE 0xA0
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
#define LTC2497_CONVERSION_TIME_MS 150ULL
struct ltc2497core_driverdata {
struct regulator *ref;
ktime_t time_prev;
u8 addr_prev;
int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
u8 address, int *val);
};
int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev);
void ltc2497core_remove(struct iio_dev *indio_dev);
MODULE_IMPORT_NS(LTC2497);

View File

@ -115,22 +115,17 @@ enum max9611_conf_ids {
* where data shall be read from
*/
static const unsigned int max9611_mux_conf[][2] = {
/* CONF_SENSE_1x */
{ MAX9611_MUX_SENSE_1x, MAX9611_REG_CSA_DATA },
/* CONF_SENSE_4x */
{ MAX9611_MUX_SENSE_4x, MAX9611_REG_CSA_DATA },
/* CONF_SENSE_8x */
{ MAX9611_MUX_SENSE_8x, MAX9611_REG_CSA_DATA },
/* CONF_IN_VOLT */
{ MAX9611_INPUT_VOLT, MAX9611_REG_RS_DATA },
/* CONF_TEMP */
{ MAX9611_MUX_TEMP, MAX9611_REG_TEMP_DATA },
[CONF_SENSE_1x] = { MAX9611_MUX_SENSE_1x, MAX9611_REG_CSA_DATA },
[CONF_SENSE_4x] = { MAX9611_MUX_SENSE_4x, MAX9611_REG_CSA_DATA },
[CONF_SENSE_8x] = { MAX9611_MUX_SENSE_8x, MAX9611_REG_CSA_DATA },
[CONF_IN_VOLT] = { MAX9611_INPUT_VOLT, MAX9611_REG_RS_DATA },
[CONF_TEMP] = { MAX9611_MUX_TEMP, MAX9611_REG_TEMP_DATA },
};
enum max9611_csa_gain {
CSA_GAIN_1x,
CSA_GAIN_4x,
CSA_GAIN_8x,
CSA_GAIN_1x = CONF_SENSE_1x,
CSA_GAIN_4x = CONF_SENSE_4x,
CSA_GAIN_8x = CONF_SENSE_8x,
};
enum max9611_csa_gain_params {
@ -148,18 +143,9 @@ enum max9611_csa_gain_params {
* value; use this structure to retrieve the correct LSB and offset values.
*/
static const unsigned int max9611_gain_conf[][2] = {
{ /* [0] CSA_GAIN_1x */
MAX9611_CSA_1X_LSB_nV,
MAX9611_CSA_1X_OFFS_RAW,
},
{ /* [1] CSA_GAIN_4x */
MAX9611_CSA_4X_LSB_nV,
MAX9611_CSA_4X_OFFS_RAW,
},
{ /* [2] CSA_GAIN_8x */
MAX9611_CSA_8X_LSB_nV,
MAX9611_CSA_8X_OFFS_RAW,
},
[CSA_GAIN_1x] = { MAX9611_CSA_1X_LSB_nV, MAX9611_CSA_1X_OFFS_RAW, },
[CSA_GAIN_4x] = { MAX9611_CSA_4X_LSB_nV, MAX9611_CSA_4X_OFFS_RAW, },
[CSA_GAIN_8x] = { MAX9611_CSA_8X_LSB_nV, MAX9611_CSA_8X_OFFS_RAW, },
};
enum max9611_chan_addrs {

View File

@ -280,21 +280,21 @@ out:
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
.eoc1_msk = STM32F4_EOC1,
.eoc2_msk = STM32F4_EOC2,
.eoc3_msk = STM32F4_EOC3,
.eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1,
.eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2,
.eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3,
.ier = STM32F4_ADC_CR1,
.eocie_msk = STM32F4_EOCIE,
.eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE,
};
/* STM32H7 common registers definitions */
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
.eoc1_msk = STM32H7_EOC_MST,
.eoc2_msk = STM32H7_EOC_SLV,
.eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST,
.eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV,
.ier = STM32H7_ADC_IER,
.eocie_msk = STM32H7_EOCIE,
.eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE,
};
static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {
@ -688,7 +688,8 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(priv->vref)) {
ret = PTR_ERR(priv->vref);
dev_err(&pdev->dev, "vref get failed, %d\n", ret);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "vref get failed, %d\n", ret);
return ret;
}
@ -696,7 +697,8 @@ static int stm32_adc_probe(struct platform_device *pdev)
if (IS_ERR(priv->aclk)) {
ret = PTR_ERR(priv->aclk);
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
return ret;
}
priv->aclk = NULL;
@ -706,7 +708,8 @@ static int stm32_adc_probe(struct platform_device *pdev)
if (IS_ERR(priv->bclk)) {
ret = PTR_ERR(priv->bclk);
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
return ret;
}
priv->bclk = NULL;

View File

@ -51,10 +51,12 @@
#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
/* STM32F4_ADC_SR - bit fields */
#define STM32F4_OVR BIT(5)
#define STM32F4_STRT BIT(4)
#define STM32F4_EOC BIT(1)
/* STM32F4_ADC_CR1 - bit fields */
#define STM32F4_OVRIE BIT(26)
#define STM32F4_RES_SHIFT 24
#define STM32F4_RES_MASK GENMASK(25, 24)
#define STM32F4_SCAN BIT(8)
@ -72,8 +74,11 @@
#define STM32F4_ADON BIT(0)
/* STM32F4_ADC_CSR - bit fields */
#define STM32F4_OVR3 BIT(21)
#define STM32F4_EOC3 BIT(17)
#define STM32F4_OVR2 BIT(13)
#define STM32F4_EOC2 BIT(9)
#define STM32F4_OVR1 BIT(5)
#define STM32F4_EOC1 BIT(1)
/* STM32F4_ADC_CCR - bit fields */
@ -103,10 +108,12 @@
/* STM32H7_ADC_ISR - bit fields */
#define STM32MP1_VREGREADY BIT(12)
#define STM32H7_OVR BIT(4)
#define STM32H7_EOC BIT(2)
#define STM32H7_ADRDY BIT(0)
/* STM32H7_ADC_IER - bit fields */
#define STM32H7_OVRIE STM32H7_OVR
#define STM32H7_EOCIE STM32H7_EOC
/* STM32H7_ADC_CR - bit fields */
@ -155,7 +162,9 @@ enum stm32h7_adc_dmngt {
#define STM32H7_LINCALFACT_MASK GENMASK(29, 0)
/* STM32H7_ADC_CSR - bit fields */
#define STM32H7_OVR_SLV BIT(20)
#define STM32H7_EOC_SLV BIT(18)
#define STM32H7_OVR_MST BIT(4)
#define STM32H7_EOC_MST BIT(2)
/* STM32H7_ADC_CCR - bit fields */

View File

@ -117,7 +117,9 @@ struct stm32_adc_regs {
* struct stm32_adc_regspec - stm32 registers definition
* @dr: data register offset
* @ier_eoc: interrupt enable register & eocie bitfield
* @ier_ovr: interrupt enable register & overrun bitfield
* @isr_eoc: interrupt status register & eoc bitfield
* @isr_ovr: interrupt status register & overrun bitfield
* @sqr: reference to sequence registers array
* @exten: trigger control register & bitfield
* @extsel: trigger selection register & bitfield
@ -128,7 +130,9 @@ struct stm32_adc_regs {
struct stm32_adc_regspec {
const u32 dr;
const struct stm32_adc_regs ier_eoc;
const struct stm32_adc_regs ier_ovr;
const struct stm32_adc_regs isr_eoc;
const struct stm32_adc_regs isr_ovr;
const struct stm32_adc_regs *sqr;
const struct stm32_adc_regs exten;
const struct stm32_adc_regs extsel;
@ -337,7 +341,9 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
static const struct stm32_adc_regspec stm32f4_adc_regspec = {
.dr = STM32F4_ADC_DR,
.ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE },
.ier_ovr = { STM32F4_ADC_CR1, STM32F4_OVRIE },
.isr_eoc = { STM32F4_ADC_SR, STM32F4_EOC },
.isr_ovr = { STM32F4_ADC_SR, STM32F4_OVR },
.sqr = stm32f4_sq,
.exten = { STM32F4_ADC_CR2, STM32F4_EXTEN_MASK, STM32F4_EXTEN_SHIFT },
.extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK,
@ -429,7 +435,9 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.dr = STM32H7_ADC_DR,
.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
.ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
.isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
.isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
.sqr = stm32h7_sq,
.exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
@ -506,6 +514,18 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc)
adc->cfg->regs->ier_eoc.mask);
}
static void stm32_adc_ovr_irq_enable(struct stm32_adc *adc)
{
stm32_adc_set_bits(adc, adc->cfg->regs->ier_ovr.reg,
adc->cfg->regs->ier_ovr.mask);
}
static void stm32_adc_ovr_irq_disable(struct stm32_adc *adc)
{
stm32_adc_clr_bits(adc, adc->cfg->regs->ier_ovr.reg,
adc->cfg->regs->ier_ovr.mask);
}
static void stm32_adc_set_res(struct stm32_adc *adc)
{
const struct stm32_adc_regs *res = &adc->cfg->regs->res;
@ -1205,6 +1225,19 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
}
}
static irqreturn_t stm32_adc_threaded_isr(int irq, void *data)
{
struct stm32_adc *adc = data;
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
const struct stm32_adc_regspec *regs = adc->cfg->regs;
u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg);
if (status & regs->isr_ovr.mask)
dev_err(&indio_dev->dev, "Overrun, stopping: restart needed\n");
return IRQ_HANDLED;
}
static irqreturn_t stm32_adc_isr(int irq, void *data)
{
struct stm32_adc *adc = data;
@ -1212,6 +1245,19 @@ static irqreturn_t stm32_adc_isr(int irq, void *data)
const struct stm32_adc_regspec *regs = adc->cfg->regs;
u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg);
if (status & regs->isr_ovr.mask) {
/*
* Overrun occurred on regular conversions: data for wrong
* channel may be read. Unconditionally disable interrupts
* to stop processing data and print error message.
* Restarting the capture can be done by disabling, then
* re-enabling it (e.g. write 0, then 1 to buffer/enable).
*/
stm32_adc_ovr_irq_disable(adc);
stm32_adc_conv_irq_disable(adc);
return IRQ_WAKE_THREAD;
}
if (status & regs->isr_eoc.mask) {
/* Reading DR also clears EOC status flag */
adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr);
@ -1441,6 +1487,8 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
/* Reset adc buffer index */
adc->bufi = 0;
stm32_adc_ovr_irq_enable(adc);
if (!adc->dma_chan)
stm32_adc_conv_irq_enable(adc);
@ -1481,6 +1529,8 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
if (!adc->dma_chan)
stm32_adc_conv_irq_disable(adc);
stm32_adc_ovr_irq_disable(adc);
if (adc->dma_chan)
dmaengine_terminate_sync(adc->dma_chan);
@ -1746,9 +1796,21 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev)
struct dma_slave_config config;
int ret;
adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
if (!adc->dma_chan)
adc->dma_chan = dma_request_chan(&indio_dev->dev, "rx");
if (IS_ERR(adc->dma_chan)) {
ret = PTR_ERR(adc->dma_chan);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(&indio_dev->dev,
"DMA channel request failed with %d\n",
ret);
return ret;
}
/* DMA is optional: fall back to IRQ mode */
adc->dma_chan = NULL;
return 0;
}
adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
STM32_DMA_BUFFER_SIZE,
@ -1818,8 +1880,9 @@ static int stm32_adc_probe(struct platform_device *pdev)
if (adc->irq < 0)
return adc->irq;
ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr,
0, pdev->name, adc);
ret = devm_request_threaded_irq(&pdev->dev, adc->irq, stm32_adc_isr,
stm32_adc_threaded_isr,
0, pdev->name, adc);
if (ret) {
dev_err(&pdev->dev, "failed to request IRQ\n");
return ret;

View File

@ -1204,6 +1204,8 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
stm32_dfsdm_stop_conv(adc);
stm32_dfsdm_process_data(adc, res);
stop_dfsdm:
stm32_dfsdm_stop_dfsdm(adc->dfsdm);
@ -1219,14 +1221,32 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
unsigned int spi_freq;
int ret = -EINVAL;
switch (ch->src) {
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL:
spi_freq = adc->dfsdm->spi_master_freq;
break;
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING:
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING:
spi_freq = adc->dfsdm->spi_master_freq / 2;
break;
default:
spi_freq = adc->spi_freq;
}
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = stm32_dfsdm_compute_all_osrs(indio_dev, val);
if (!ret)
if (!ret) {
dev_dbg(&indio_dev->dev,
"Sampling rate changed from (%u) to (%u)\n",
adc->sample_freq, spi_freq / val);
adc->oversamp = val;
adc->sample_freq = spi_freq / val;
}
iio_device_release_direct_mode(indio_dev);
return ret;
@ -1238,18 +1258,6 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
switch (ch->src) {
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL:
spi_freq = adc->dfsdm->spi_master_freq;
break;
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING:
case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING:
spi_freq = adc->dfsdm->spi_master_freq / 2;
break;
default:
spi_freq = adc->spi_freq;
}
ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq);
iio_device_release_direct_mode(indio_dev);
return ret;
@ -1383,9 +1391,13 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
if (!adc->dma_chan)
return -EINVAL;
adc->dma_chan = dma_request_chan(&indio_dev->dev, "rx");
if (IS_ERR(adc->dma_chan)) {
int ret = PTR_ERR(adc->dma_chan);
adc->dma_chan = NULL;
return ret;
}
adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
DFSDM_DMA_BUFFER_SIZE,
@ -1509,7 +1521,16 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
init_completion(&adc->completion);
/* Optionally request DMA */
if (stm32_dfsdm_dma_request(indio_dev)) {
ret = stm32_dfsdm_dma_request(indio_dev);
if (ret) {
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(&indio_dev->dev,
"DMA channel request failed with %d\n",
ret);
return ret;
}
dev_dbg(&indio_dev->dev, "No DMA support\n");
return 0;
}

View File

@ -12,17 +12,15 @@
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/platform_data/ads1015.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/iio/sysfs.h>
@ -33,6 +31,8 @@
#define ADS1015_DRV_NAME "ads1015"
#define ADS1015_CHANNELS 8
#define ADS1015_CONV_REG 0x00
#define ADS1015_CFG_REG 0x01
#define ADS1015_LO_THRESH_REG 0x02
@ -77,6 +77,7 @@
#define ADS1015_DEFAULT_CHAN 0
enum chip_ids {
ADSXXXX = 0,
ADS1015,
ADS1115,
};
@ -219,6 +220,12 @@ static const struct iio_event_spec ads1015_events[] = {
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
}
struct ads1015_channel_data {
bool enabled;
unsigned int pga;
unsigned int data_rate;
};
struct ads1015_thresh_data {
unsigned int comp_queue;
int high_thresh;
@ -837,65 +844,58 @@ static const struct iio_info ads1115_info = {
.attrs = &ads1115_attribute_group,
};
#ifdef CONFIG_OF
static int ads1015_get_channels_config_of(struct i2c_client *client)
static int ads1015_client_get_channels_config(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct device_node *node;
struct device *dev = &client->dev;
struct fwnode_handle *node;
int i = -1;
if (!client->dev.of_node ||
!of_get_next_child(client->dev.of_node, NULL))
return -EINVAL;
for_each_child_of_node(client->dev.of_node, node) {
device_for_each_child_node(dev, node) {
u32 pval;
unsigned int channel;
unsigned int pga = ADS1015_DEFAULT_PGA;
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
if (of_property_read_u32(node, "reg", &pval)) {
dev_err(&client->dev, "invalid reg on %pOF\n",
node);
if (fwnode_property_read_u32(node, "reg", &pval)) {
dev_err(dev, "invalid reg on %pfw\n", node);
continue;
}
channel = pval;
if (channel >= ADS1015_CHANNELS) {
dev_err(&client->dev,
"invalid channel index %d on %pOF\n",
dev_err(dev, "invalid channel index %d on %pfw\n",
channel, node);
continue;
}
if (!of_property_read_u32(node, "ti,gain", &pval)) {
if (!fwnode_property_read_u32(node, "ti,gain", &pval)) {
pga = pval;
if (pga > 6) {
dev_err(&client->dev, "invalid gain on %pOF\n",
node);
of_node_put(node);
dev_err(dev, "invalid gain on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
}
}
if (!of_property_read_u32(node, "ti,datarate", &pval)) {
if (!fwnode_property_read_u32(node, "ti,datarate", &pval)) {
data_rate = pval;
if (data_rate > 7) {
dev_err(&client->dev,
"invalid data_rate on %pOF\n",
node);
of_node_put(node);
dev_err(dev, "invalid data_rate on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
}
}
data->channel_data[channel].pga = pga;
data->channel_data[channel].data_rate = data_rate;
i++;
}
return 0;
return i < 0 ? -EINVAL : 0;
}
#endif
static void ads1015_get_channels_config(struct i2c_client *client)
{
@ -903,19 +903,10 @@ static void ads1015_get_channels_config(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
/* prefer platform data */
if (pdata) {
memcpy(data->channel_data, pdata->channel_data,
sizeof(data->channel_data));
if (!ads1015_client_get_channels_config(client))
return;
}
#ifdef CONFIG_OF
if (!ads1015_get_channels_config_of(client))
return;
#endif
/* fallback on default configuration */
for (k = 0; k < ADS1015_CHANNELS; ++k) {
data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
@ -953,9 +944,8 @@ static int ads1015_probe(struct i2c_client *client,
indio_dev->name = ADS1015_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->dev.of_node)
chip = (enum chip_ids)of_device_get_match_data(&client->dev);
else
chip = (enum chip_ids)device_get_match_data(&client->dev);
if (chip == ADSXXXX)
chip = id->driver_data;
switch (chip) {
case ADS1015:
@ -970,6 +960,9 @@ static int ads1015_probe(struct i2c_client *client,
indio_dev->info = &ads1115_info;
data->data_rate = (unsigned int *) &ads1115_data_rate;
break;
default:
dev_err(&client->dev, "Unknown chip %d\n", chip);
return -EINVAL;
}
data->event_channel = ADS1015_CHANNELS;

View File

@ -602,7 +602,7 @@ static int ti_ads7950_probe(struct spi_device *spi)
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) {
dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
dev_err(&spi->dev, "Failed to get regulator \"vref\"\n");
ret = PTR_ERR(st->reg);
goto error_destroy_mutex;
}

View File

@ -476,7 +476,7 @@ static struct iio_dma_buffer_block *iio_dma_buffer_dequeue(
* @n: Number of bytes to read
* @user_buffer: Userspace buffer to copy the data to
*
* Should be used as the read_first_n callback for iio_buffer_access_ops
* Should be used as the read callback for iio_buffer_access_ops
* struct for DMA buffers.
*/
int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n,

View File

@ -10,8 +10,10 @@
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
#include <linux/iio/buffer-dma.h>
@ -107,7 +109,7 @@ static void iio_dmaengine_buffer_release(struct iio_buffer *buf)
}
static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
.read_first_n = iio_dma_buffer_read,
.read = iio_dma_buffer_read,
.set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum,
.set_length = iio_dma_buffer_set_length,
.request_update = iio_dma_buffer_request_update,
@ -125,6 +127,24 @@ static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = {
.abort = iio_dmaengine_buffer_abort,
};
static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(indio_dev->buffer);
return sprintf(buf, "%u\n", dmaengine_buffer->align);
}
static IIO_DEVICE_ATTR(length_align_bytes, 0444,
iio_dmaengine_buffer_get_length_align, NULL, 0);
static const struct attribute *iio_dmaengine_buffer_attrs[] = {
&iio_dev_attr_length_align_bytes.dev_attr.attr,
NULL,
};
/**
* iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
* @dev: Parent device for the buffer
@ -150,7 +170,7 @@ struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
if (!dmaengine_buffer)
return ERR_PTR(-ENOMEM);
chan = dma_request_slave_channel_reason(dev, channel);
chan = dma_request_chan(dev, channel);
if (IS_ERR(chan)) {
ret = PTR_ERR(chan);
goto err_free;
@ -178,6 +198,8 @@ struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev,
&iio_dmaengine_default_ops);
iio_buffer_set_attrs(&dmaengine_buffer->queue.buffer,
iio_dmaengine_buffer_attrs);
dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops;
@ -206,3 +228,7 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
iio_buffer_put(buffer);
}
EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("DMA buffer for the IIO framework");
MODULE_LICENSE("GPL");

View File

@ -98,8 +98,7 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
return 0;
}
static int iio_read_first_n_kfifo(struct iio_buffer *r,
size_t n, char __user *buf)
static int iio_read_kfifo(struct iio_buffer *r, size_t n, char __user *buf)
{
int ret, copied;
struct iio_kfifo *kf = iio_to_kfifo(r);
@ -141,7 +140,7 @@ static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
static const struct iio_buffer_access_funcs kfifo_access_funcs = {
.store_to = &iio_store_to_kfifo,
.read_first_n = &iio_read_first_n_kfifo,
.read = &iio_read_kfifo,
.data_available = iio_kfifo_buf_data_available,
.request_update = &iio_request_update_kfifo,
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,

View File

@ -4,7 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-sensor.o
obj-$(CONFIG_BME680) += bme680_core.o
obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* atlas-ph-sensor.c - Support for Atlas Scientific OEM pH-SM sensor
* atlas-sensor.c - Support for Atlas Scientific OEM SM sensors
*
* Copyright (C) 2015-2018 Matt Ranostay
* Copyright (C) 2015-2019 Konsulko Group
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
@ -14,7 +14,6 @@
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/irq_work.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
@ -25,8 +24,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/pm_runtime.h>
#define ATLAS_REGMAP_NAME "atlas_ph_regmap"
#define ATLAS_DRV_NAME "atlas_ph"
#define ATLAS_REGMAP_NAME "atlas_regmap"
#define ATLAS_DRV_NAME "atlas"
#define ATLAS_REG_DEV_TYPE 0x00
#define ATLAS_REG_DEV_VERSION 0x01
@ -87,6 +86,16 @@ static const struct regmap_config atlas_regmap_config = {
.val_bits = 8,
};
static int atlas_buffer_num_channels(const struct iio_chan_spec *spec)
{
int idx = 0;
for (; spec->type != IIO_TIMESTAMP; spec++)
idx++;
return idx;
};
static const struct iio_chan_spec atlas_ph_channels[] = {
{
.type = IIO_PH,
@ -355,11 +364,12 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private)
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct atlas_data *data = iio_priv(indio_dev);
int channels = atlas_buffer_num_channels(data->chip->channels);
int ret;
ret = regmap_bulk_read(data->regmap, data->chip->data_reg,
(u8 *) &data->buffer,
sizeof(__be32) * (data->chip->num_channels - 2));
sizeof(__be32) * channels);
if (!ret)
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
@ -681,5 +691,5 @@ static struct i2c_driver atlas_driver = {
module_i2c_driver(atlas_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("Atlas Scientific pH-SM sensor");
MODULE_DESCRIPTION("Atlas Scientific SM sensors");
MODULE_LICENSE("GPL");

View File

@ -7,7 +7,7 @@
#define __SSP_SENSORHUB_H__
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/common/ssp_sensors.h>
#include <linux/iio/iio.h>
#include <linux/spi/spi.h>
@ -168,9 +168,9 @@ struct ssp_sensorhub_info {
* @fw_dl_state: firmware download state
* @comm_lock: lock protecting the handshake
* @pending_lock: lock protecting pending list and completion
* @mcu_reset_gpio: mcu reset line
* @ap_mcu_gpio: ap to mcu gpio line
* @mcu_ap_gpio: mcu to ap gpio line
* @mcu_reset_gpiod: mcu reset line
* @ap_mcu_gpiod: ap to mcu gpio line
* @mcu_ap_gpiod: mcu to ap gpio line
* @pending_list: pending list for messages queued to be sent/read
* @sensor_devs: registered IIO devices table
* @enable_refcount: enable reference count for wdt (watchdog timer)
@ -212,9 +212,9 @@ struct ssp_data {
struct mutex comm_lock;
struct mutex pending_lock;
int mcu_reset_gpio;
int ap_mcu_gpio;
int mcu_ap_gpio;
struct gpio_desc *mcu_reset_gpiod;
struct gpio_desc *ap_mcu_gpiod;
struct gpio_desc *mcu_ap_gpiod;
struct list_head pending_list;

View File

@ -9,7 +9,6 @@
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include "ssp.h"
@ -61,9 +60,9 @@ static const struct mfd_cell sensorhub_sensor_devs[] = {
static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)
{
gpio_set_value(data->mcu_reset_gpio, 0);
gpiod_set_value(data->mcu_reset_gpiod, 0);
usleep_range(1000, 1200);
gpio_set_value(data->mcu_reset_gpio, 1);
gpiod_set_value(data->mcu_reset_gpiod, 1);
msleep(50);
}
@ -441,7 +440,6 @@ MODULE_DEVICE_TABLE(of, ssp_of_match);
static struct ssp_data *ssp_parse_dt(struct device *dev)
{
int ret;
struct ssp_data *data;
struct device_node *node = dev->of_node;
const struct of_device_id *match;
@ -450,26 +448,17 @@ static struct ssp_data *ssp_parse_dt(struct device *dev)
if (!data)
return NULL;
data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
if (data->mcu_ap_gpio < 0)
data->mcu_ap_gpiod = devm_gpiod_get(dev, "mcu-ap", GPIOD_IN);
if (IS_ERR(data->mcu_ap_gpiod))
return NULL;
data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
if (data->ap_mcu_gpio < 0)
data->ap_mcu_gpiod = devm_gpiod_get(dev, "ap-mcu", GPIOD_OUT_HIGH);
if (IS_ERR(data->ap_mcu_gpiod))
return NULL;
data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
if (data->mcu_reset_gpio < 0)
return NULL;
ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
"ap-mcu-gpios");
if (ret)
return NULL;
ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
if (ret)
data->mcu_reset_gpiod = devm_gpiod_get(dev, "mcu-reset",
GPIOD_OUT_HIGH);
if (IS_ERR(data->mcu_reset_gpiod))
return NULL;
match = of_match_node(ssp_of_match, node);

View File

@ -155,9 +155,9 @@ static int ssp_check_lines(struct ssp_data *data, bool state)
{
int delay_cnt = 0;
gpio_set_value_cansleep(data->ap_mcu_gpio, state);
gpiod_set_value_cansleep(data->ap_mcu_gpiod, state);
while (gpio_get_value_cansleep(data->mcu_ap_gpio) != state) {
while (gpiod_get_value_cansleep(data->mcu_ap_gpiod) != state) {
usleep_range(3000, 3500);
if (data->shut_down || delay_cnt++ > 500) {
@ -165,7 +165,7 @@ static int ssp_check_lines(struct ssp_data *data, bool state)
__func__, state);
if (!state)
gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
gpiod_set_value_cansleep(data->ap_mcu_gpiod, 1);
return -ETIMEDOUT;
}
@ -197,7 +197,7 @@ static int ssp_do_transfer(struct ssp_data *data, struct ssp_msg *msg,
status = spi_write(data->spi, msg->buffer, SSP_HEADER_SIZE);
if (status < 0) {
gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
gpiod_set_value_cansleep(data->ap_mcu_gpiod, 1);
dev_err(SSP_DEV, "%s spi_write fail\n", __func__);
goto _error_locked;
}

View File

@ -12,9 +12,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
@ -319,63 +318,49 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
return 0;
}
#ifdef CONFIG_OF
static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
static struct st_sensors_platform_data *st_sensors_dev_probe(struct device *dev,
struct st_sensors_platform_data *defdata)
{
struct st_sensors_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 val;
if (!np)
if (!dev_fwnode(dev))
return NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2))
if (!device_property_read_u32(dev, "st,drdy-int-pin", &val) && (val <= 2))
pdata->drdy_int_pin = (u8) val;
else
pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;
pdata->open_drain = of_property_read_bool(np, "drive-open-drain");
pdata->open_drain = device_property_read_bool(dev, "drive-open-drain");
return pdata;
}
/**
* st_sensors_of_name_probe() - device tree probe for ST sensor name
* st_sensors_dev_name_probe() - device probe for ST sensor name
* @dev: driver model representation of the device.
* @match: the OF match table for the device, containing compatible strings
* but also a .data field with the corresponding internal kernel name
* used by this sensor.
* @name: device name buffer reference.
* @len: device name buffer length.
*
* In effect this function matches a compatible string to an internal kernel
* In effect this function matches an ID to an internal kernel
* name for a certain sensor device, so that the rest of the autodetection can
* rely on that name from this point on. I2C/SPI devices will be renamed
* to match the internal kernel convention.
*/
void st_sensors_of_name_probe(struct device *dev,
const struct of_device_id *match,
char *name, int len)
void st_sensors_dev_name_probe(struct device *dev, char *name, int len)
{
const struct of_device_id *of_id;
const void *match;
of_id = of_match_device(match, dev);
if (!of_id || !of_id->data)
match = device_get_match_data(dev);
if (!match)
return;
/* The name from the OF match takes precedence if present */
strlcpy(name, of_id->data, len);
/* The name from the match takes precedence if present */
strlcpy(name, match, len);
}
EXPORT_SYMBOL(st_sensors_of_name_probe);
#else
static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
struct st_sensors_platform_data *defdata)
{
return NULL;
}
#endif
EXPORT_SYMBOL(st_sensors_dev_name_probe);
int st_sensors_init_sensor(struct iio_dev *indio_dev,
struct st_sensors_platform_data *pdata)
@ -385,7 +370,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
int err = 0;
/* If OF/DT pdata exists, it will take precedence of anything else */
of_pdata = st_sensors_of_probe(indio_dev->dev.parent, pdata);
of_pdata = st_sensors_dev_probe(indio_dev->dev.parent, pdata);
if (of_pdata)
pdata = of_pdata;

View File

@ -11,8 +11,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_i2c.h>
@ -68,25 +66,6 @@ int st_sensors_i2c_configure(struct iio_dev *indio_dev,
}
EXPORT_SYMBOL(st_sensors_i2c_configure);
#ifdef CONFIG_ACPI
int st_sensors_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *acpi_id;
kernel_ulong_t driver_data = 0;
if (ACPI_HANDLE(dev)) {
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!acpi_id) {
dev_err(dev, "No driver data\n");
return -EINVAL;
}
driver_data = acpi_id->driver_data;
}
return driver_data;
}
EXPORT_SYMBOL(st_sensors_match_acpi_device);
#endif
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
MODULE_LICENSE("GPL v2");

View File

@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_spi.h>
@ -37,14 +38,15 @@ static const struct regmap_config st_sensors_spi_regmap_multiread_bit_config = {
*/
static bool st_sensors_is_spi_3_wire(struct spi_device *spi)
{
struct device_node *np = spi->dev.of_node;
struct st_sensors_platform_data *pdata;
struct device *dev = &spi->dev;
pdata = (struct st_sensors_platform_data *)spi->dev.platform_data;
if ((np && of_property_read_bool(np, "spi-3wire")) ||
(pdata && pdata->spi_3wire)) {
if (device_property_read_bool(dev, "spi-3wire"))
return true;
pdata = (struct st_sensors_platform_data *)dev->platform_data;
if (pdata && pdata->spi_3wire)
return true;
}
return false;
}

View File

@ -19,6 +19,9 @@
/**
* st_sensors_new_samples_available() - check if more samples came in
* @indio_dev: IIO device reference.
* @sdata: Sensor data.
*
* returns:
* 0 - no new samples available
* 1 - new samples available

View File

@ -15,7 +15,6 @@
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/property.h>
#include <dt-bindings/iio/adi,ad5592r.h>

View File

@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -202,7 +201,6 @@ static int ad7303_probe(struct spi_device *spi)
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct ad7303_state *st;
bool ext_ref;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@ -224,24 +222,15 @@ static int ad7303_probe(struct spi_device *spi)
if (ret)
return ret;
if (spi->dev.of_node) {
ext_ref = of_property_read_bool(spi->dev.of_node,
"REF-supply");
} else {
struct ad7303_platform_data *pdata = spi->dev.platform_data;
if (pdata && pdata->use_external_ref)
ext_ref = true;
else
ext_ref = false;
st->vref_reg = devm_regulator_get_optional(&spi->dev, "REF");
if (IS_ERR(st->vref_reg)) {
ret = PTR_ERR(st->vref_reg);
if (ret != -ENODEV)
goto err_disable_vdd_reg;
st->vref_reg = NULL;
}
if (ext_ref) {
st->vref_reg = devm_regulator_get(&spi->dev, "REF");
if (IS_ERR(st->vref_reg)) {
ret = PTR_ERR(st->vref_reg);
goto err_disable_vdd_reg;
}
if (st->vref_reg) {
ret = regulator_enable(st->vref_reg);
if (ret)
goto err_disable_vdd_reg;

View File

@ -20,13 +20,11 @@
/**
* struct stm32_dac_priv - stm32 DAC core private data
* @pclk: peripheral clock common for all DACs
* @rst: peripheral reset control
* @vref: regulator reference
* @common: Common data for all DAC instances
*/
struct stm32_dac_priv {
struct clk *pclk;
struct reset_control *rst;
struct regulator *vref;
struct stm32_dac_common common;
};
@ -94,6 +92,7 @@ static int stm32_dac_probe(struct platform_device *pdev)
struct regmap *regmap;
struct resource *res;
void __iomem *mmio;
struct reset_control *rst;
int ret;
if (!dev->of_node)
@ -148,11 +147,19 @@ static int stm32_dac_probe(struct platform_device *pdev)
priv->common.vref_mv = ret / 1000;
dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
priv->rst = devm_reset_control_get_exclusive(dev, NULL);
if (!IS_ERR(priv->rst)) {
reset_control_assert(priv->rst);
rst = devm_reset_control_get_optional_exclusive(dev, NULL);
if (rst) {
if (IS_ERR(rst)) {
ret = PTR_ERR(rst);
if (ret != -EPROBE_DEFER)
dev_err(dev, "reset get failed, %d\n", ret);
goto err_hw_stop;
}
reset_control_assert(rst);
udelay(2);
reset_control_deassert(priv->rst);
reset_control_deassert(rst);
}
if (cfg && cfg->has_hfsel) {

View File

@ -14,11 +14,10 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/gcd.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <asm/div64.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -34,6 +33,7 @@ enum {
struct adf4350_state {
struct spi_device *spi;
struct regulator *reg;
struct gpio_desc *lock_detect_gpiod;
struct adf4350_platform_data *pdata;
struct clk *clk;
unsigned long clkin;
@ -61,7 +61,6 @@ static struct adf4350_platform_data default_pdata = {
.r3_user_settings = ADF4350_REG3_12BIT_CLKDIV_MODE(0),
.r4_user_settings = ADF4350_REG4_OUTPUT_PWR(3) |
ADF4350_REG4_MUTE_TILL_LOCK_EN,
.gpio_lock_detect = -1,
};
static int adf4350_sync_config(struct adf4350_state *st)
@ -317,8 +316,8 @@ static ssize_t adf4350_read(struct iio_dev *indio_dev,
(u64)st->fpfd;
do_div(val, st->r1_mod * (1 << st->r4_rf_div_sel));
/* PLL unlocked? return error */
if (gpio_is_valid(st->pdata->gpio_lock_detect))
if (!gpio_get_value(st->pdata->gpio_lock_detect)) {
if (st->lock_detect_gpiod)
if (!gpiod_get_value(st->lock_detect_gpiod)) {
dev_dbg(&st->spi->dev, "PLL un-locked\n");
ret = -EBUSY;
}
@ -381,7 +380,6 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
struct device_node *np = dev->of_node;
struct adf4350_platform_data *pdata;
unsigned int tmp;
int ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@ -401,12 +399,6 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
of_property_read_u32(np, "adi,reference-div-factor", &tmp);
pdata->ref_div_factor = tmp;
ret = of_get_gpio(np, 0);
if (ret < 0)
pdata->gpio_lock_detect = -1;
else
pdata->gpio_lock_detect = ret;
pdata->ref_doubler_en = of_property_read_bool(np,
"adi,reference-doubler-enable");
pdata->ref_div2_en = of_property_read_bool(np,
@ -561,16 +553,10 @@ static int adf4350_probe(struct spi_device *spi)
memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
if (gpio_is_valid(pdata->gpio_lock_detect)) {
ret = devm_gpio_request(&spi->dev, pdata->gpio_lock_detect,
indio_dev->name);
if (ret) {
dev_err(&spi->dev, "fail to request lock detect GPIO-%d",
pdata->gpio_lock_detect);
goto error_disable_reg;
}
gpio_direction_input(pdata->gpio_lock_detect);
}
st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL,
GPIOD_IN);
if (IS_ERR(st->lock_detect_gpiod))
return PTR_ERR(st->lock_detect_gpiod);
if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency);

View File

@ -75,26 +75,26 @@ config BMG160_SPI
select REGMAP_SPI
config FXAS21002C
tristate "NXP FXAS21002C Gyro Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select FXAS21002C_I2C if (I2C)
select FXAS21002C_SPI if (SPI)
depends on (I2C || SPI_MASTER)
help
Say yes here to build support for NXP FXAS21002C Tri-axis Gyro
Sensor driver connected via I2C or SPI.
tristate "NXP FXAS21002C Gyro Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select FXAS21002C_I2C if (I2C)
select FXAS21002C_SPI if (SPI)
depends on (I2C || SPI_MASTER)
help
Say yes here to build support for NXP FXAS21002C Tri-axis Gyro
Sensor driver connected via I2C or SPI.
This driver can also be built as a module. If so, the module
will be called fxas21002c_i2c or fxas21002c_spi.
This driver can also be built as a module. If so, the module
will be called fxas21002c_i2c or fxas21002c_spi.
config FXAS21002C_I2C
tristate
select REGMAP_I2C
tristate
select REGMAP_I2C
config FXAS21002C_SPI
tristate
select REGMAP_SPI
tristate
select REGMAP_SPI
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB

View File

@ -59,6 +59,7 @@
struct adis16136_chip_info {
unsigned int precision;
unsigned int fullscale;
const struct adis_timeout *timeouts;
};
struct adis16136 {
@ -185,12 +186,12 @@ static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
}
static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
static int __adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
{
uint16_t t;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
if (ret)
return ret;
@ -224,10 +225,13 @@ static ssize_t adis16136_read_frequency(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
int ret;
ret = adis16136_get_freq(adis16136, &freq);
mutex_lock(slock);
ret = __adis16136_get_freq(adis16136, &freq);
mutex_unlock(slock);
if (ret)
return ret;
@ -252,42 +256,50 @@ static const unsigned adis16136_3db_divisors[] = {
static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
int i, ret;
ret = adis16136_get_freq(adis16136, &freq);
mutex_lock(slock);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
return ret;
goto out_unlock;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
if (freq / adis16136_3db_divisors[i] >= val)
break;
}
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
out_unlock:
mutex_unlock(slock);
return ret;
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
uint16_t val16;
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
&val16);
if (ret)
goto err_unlock;
ret = adis16136_get_freq(adis16136, &freq);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
goto err_unlock;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
err_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret ? ret : IIO_VAL_INT;
}
@ -460,7 +472,6 @@ static const struct adis_data adis16136_data = {
.msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
.self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
.startup_delay = 80,
.read_delay = 10,
.write_delay = 10,
@ -479,30 +490,63 @@ enum adis16136_id {
ID_ADIS16137,
};
static const struct adis_timeout adis16133_timeouts = {
.reset_ms = 75,
.sw_reset_ms = 75,
.self_test_ms = 50,
};
static const struct adis_timeout adis16136_timeouts = {
.reset_ms = 128,
.sw_reset_ms = 75,
.self_test_ms = 245,
};
static const struct adis16136_chip_info adis16136_chip_info[] = {
[ID_ADIS16133] = {
.precision = IIO_DEGREE_TO_RAD(1200),
.fullscale = 24000,
.timeouts = &adis16133_timeouts,
},
[ID_ADIS16135] = {
.precision = IIO_DEGREE_TO_RAD(300),
.fullscale = 24000,
.timeouts = &adis16133_timeouts,
},
[ID_ADIS16136] = {
.precision = IIO_DEGREE_TO_RAD(450),
.fullscale = 24623,
.timeouts = &adis16136_timeouts,
},
[ID_ADIS16137] = {
.precision = IIO_DEGREE_TO_RAD(1000),
.fullscale = 24609,
.timeouts = &adis16136_timeouts,
},
};
static struct adis_data *adis16136_adis_data_alloc(struct adis16136 *st,
struct device *dev)
{
struct adis_data *data;
data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
memcpy(data, &adis16136_data, sizeof(*data));
data->timeouts = st->chip_info->timeouts;
return data;
}
static int adis16136_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct adis16136 *adis16136;
struct iio_dev *indio_dev;
const struct adis_data *adis16136_data;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136));
@ -521,7 +565,11 @@ static int adis16136_probe(struct spi_device *spi)
indio_dev->info = &adis16136_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data);
adis16136_data = adis16136_adis_data_alloc(adis16136, &spi->dev);
if (IS_ERR(adis16136_data))
return PTR_ERR(adis16136_data);
ret = adis_init(&adis16136->adis, indio_dev, spi, adis16136_data);
if (ret)
return ret;

View File

@ -293,7 +293,7 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&indio_dev->mlock);
mutex_lock(&adis->state_lock);
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
@ -308,9 +308,9 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
else
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&adis->state_lock);
return ret;
}
return -EINVAL;
@ -332,6 +332,12 @@ static const char * const adis1620_status_error_msgs[] = {
[ADIS16260_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 4.75",
};
static const struct adis_timeout adis16260_timeouts = {
.reset_ms = ADIS16260_STARTUP_DELAY,
.sw_reset_ms = ADIS16260_STARTUP_DELAY,
.self_test_ms = ADIS16260_STARTUP_DELAY,
};
static const struct adis_data adis16260_data = {
.write_delay = 30,
.read_delay = 30,
@ -340,7 +346,7 @@ static const struct adis_data adis16260_data = {
.diag_stat_reg = ADIS16260_DIAG_STAT,
.self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,
.startup_delay = ADIS16260_STARTUP_DELAY,
.timeouts = &adis16260_timeouts,
.status_error_msgs = adis1620_status_error_msgs,
.status_error_mask = BIT(ADIS16260_DIAG_STAT_FLASH_CHK_BIT) |

View File

@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>

View File

@ -28,7 +28,7 @@
* struct st_sensors_platform_data - gyro platform data
* @drdy_int_pin: DRDY on gyros is available only on INT2 pin.
*/
static const struct st_sensors_platform_data gyro_pdata = {
static __maybe_unused const struct st_sensors_platform_data gyro_pdata = {
.drdy_int_pin = 2,
};

View File

@ -138,7 +138,6 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
[2] = LSM330DLC_GYRO_DEV_NAME,
[3] = L3G4IS_GYRO_DEV_NAME,
[4] = LSM330_GYRO_DEV_NAME,
[5] = LSM9DS0_GYRO_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
.odr = {
@ -208,6 +207,80 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.multi_read_bit = true,
.bootime = 2,
},
{
.wai = 0xd4,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM9DS0_GYRO_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
.odr = {
.addr = 0x20,
.mask = GENMASK(7, 6),
.odr_avl = {
{ .hz = 95, .value = 0x00, },
{ .hz = 190, .value = 0x01, },
{ .hz = 380, .value = 0x02, },
{ .hz = 760, .value = 0x03, },
},
},
.pw = {
.addr = 0x20,
.mask = BIT(3),
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = 0x23,
.mask = GENMASK(5, 4),
.fs_avl = {
[0] = {
.num = ST_GYRO_FS_AVL_245DPS,
.value = 0x00,
.gain = IIO_DEGREE_TO_RAD(8750),
},
[1] = {
.num = ST_GYRO_FS_AVL_500DPS,
.value = 0x01,
.gain = IIO_DEGREE_TO_RAD(17500),
},
[2] = {
.num = ST_GYRO_FS_AVL_2000DPS,
.value = 0x02,
.gain = IIO_DEGREE_TO_RAD(70000),
},
},
},
.bdu = {
.addr = 0x23,
.mask = BIT(7),
},
.drdy_irq = {
.int2 = {
.addr = 0x22,
.mask = BIT(3),
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = GENMASK(2, 0),
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
},
{
.wai = 0xd7,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,

View File

@ -17,7 +17,6 @@
#include <linux/iio/common/st_sensors_i2c.h>
#include "st_gyro.h"
#ifdef CONFIG_OF
static const struct of_device_id st_gyro_of_match[] = {
{
.compatible = "st,l3g4200d-gyro",
@ -58,9 +57,6 @@ static const struct of_device_id st_gyro_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
#else
#define st_gyro_of_match NULL
#endif
static int st_gyro_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@ -70,8 +66,7 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&client->dev, st_gyro_of_match,
client->name, sizeof(client->name));
st_sensors_dev_name_probe(&client->dev, client->name, sizeof(client->name));
settings = st_gyro_get_settings(client->name);
if (!settings) {
@ -122,7 +117,7 @@ MODULE_DEVICE_TABLE(i2c, st_gyro_id_table);
static struct i2c_driver st_gyro_driver = {
.driver = {
.name = "st-gyro-i2c",
.of_match_table = of_match_ptr(st_gyro_of_match),
.of_match_table = st_gyro_of_match,
},
.probe = st_gyro_i2c_probe,
.remove = st_gyro_i2c_remove,

View File

@ -17,7 +17,6 @@
#include <linux/iio/common/st_sensors_spi.h>
#include "st_gyro.h"
#ifdef CONFIG_OF
/*
* For new single-chip sensors use <device_name> as compatible string.
* For old single-chip devices keep <device_name>-gyro to maintain
@ -63,9 +62,6 @@ static const struct of_device_id st_gyro_of_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, st_gyro_of_match);
#else
#define st_gyro_of_match NULL
#endif
static int st_gyro_spi_probe(struct spi_device *spi)
{
@ -74,8 +70,7 @@ static int st_gyro_spi_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&spi->dev, st_gyro_of_match,
spi->modalias, sizeof(spi->modalias));
st_sensors_dev_name_probe(&spi->dev, spi->modalias, sizeof(spi->modalias));
settings = st_gyro_get_settings(spi->modalias);
if (!settings) {
@ -126,7 +121,7 @@ MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
static struct spi_driver st_gyro_driver = {
.driver = {
.name = "st-gyro-spi",
.of_match_table = of_match_ptr(st_gyro_of_match),
.of_match_table = st_gyro_of_match,
},
.probe = st_gyro_spi_probe,
.remove = st_gyro_spi_remove,

View File

@ -174,7 +174,6 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
struct iio_dev *iio = data;
struct dht11 *dht11 = iio_priv(iio);
/* TODO: Consider making the handler safe for IRQ sharing */
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
dht11->edges[dht11->num_edges].ts = ktime_get_boottime_ns();
dht11->edges[dht11->num_edges++].value =

View File

@ -24,13 +24,6 @@
#define HTS221_REG_CNTRL1_ADDR 0x20
#define HTS221_REG_CNTRL2_ADDR 0x21
#define HTS221_REG_AVG_ADDR 0x10
#define HTS221_REG_H_OUT_L 0x28
#define HTS221_REG_T_OUT_L 0x2a
#define HTS221_HUMIDITY_AVG_MASK 0x07
#define HTS221_TEMP_AVG_MASK 0x38
#define HTS221_ODR_MASK 0x03
#define HTS221_BDU_MASK BIT(2)
#define HTS221_ENABLE_MASK BIT(7)
@ -66,8 +59,8 @@ static const struct hts221_odr hts221_odr_table[] = {
static const struct hts221_avg hts221_avg_list[] = {
{
.addr = HTS221_REG_AVG_ADDR,
.mask = HTS221_HUMIDITY_AVG_MASK,
.addr = 0x10,
.mask = 0x07,
.avg_avl = {
4, /* 0.4 %RH */
8, /* 0.3 %RH */
@ -80,8 +73,8 @@ static const struct hts221_avg hts221_avg_list[] = {
},
},
{
.addr = HTS221_REG_AVG_ADDR,
.mask = HTS221_TEMP_AVG_MASK,
.addr = 0x10,
.mask = 0x38,
.avg_avl = {
2, /* 0.08 degC */
4, /* 0.05 degC */
@ -98,7 +91,7 @@ static const struct hts221_avg hts221_avg_list[] = {
static const struct iio_chan_spec hts221_channels[] = {
{
.type = IIO_HUMIDITYRELATIVE,
.address = HTS221_REG_H_OUT_L,
.address = 0x28,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
@ -114,7 +107,7 @@ static const struct iio_chan_spec hts221_channels[] = {
},
{
.type = IIO_TEMP,
.address = HTS221_REG_T_OUT_L,
.address = 0x2a,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |

View File

@ -42,14 +42,14 @@ struct poll_table_struct;
__poll_t iio_buffer_poll(struct file *filp,
struct poll_table_struct *wait);
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps);
ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps);
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
#define iio_buffer_poll_addr (&iio_buffer_poll)
#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
#define iio_buffer_read_outer_addr (&iio_buffer_read_outer)
void iio_disable_all_buffers(struct iio_dev *indio_dev);
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
@ -57,7 +57,7 @@ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
#else
#define iio_buffer_poll_addr NULL
#define iio_buffer_read_first_n_outer_addr NULL
#define iio_buffer_read_outer_addr NULL
static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{

View File

@ -26,7 +26,14 @@
#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
#define ADIS_GLOB_CMD_SW_RESET BIT(7)
int adis_write_reg(struct adis *adis, unsigned int reg,
/**
* __adis_write_reg() - write N bytes to register (unlocked version)
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @value: The value to write to device (up to 4 bytes)
* @size: The size of the @value (in bytes)
*/
int __adis_write_reg(struct adis *adis, unsigned int reg,
unsigned int value, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
@ -38,7 +45,8 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
@ -46,7 +54,8 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
@ -54,24 +63,25 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 6,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->write_delay,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 8,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->write_delay,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
},
};
mutex_lock(&adis->txrx_lock);
spi_message_init(&msg);
if (adis->current_page != page) {
@ -96,8 +106,7 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
adis->tx[3] = value & 0xff;
break;
default:
ret = -EINVAL;
goto out_unlock;
return -EINVAL;
}
xfers[size].cs_change = 0;
@ -113,20 +122,18 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
adis->current_page = page;
}
out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_write_reg);
EXPORT_SYMBOL_GPL(__adis_write_reg);
/**
* adis_read_reg() - read 2 bytes from a 16-bit register
* __adis_read_reg() - read N bytes from register (unlocked version)
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
* @size: The size of the @val buffer
*/
int adis_read_reg(struct adis *adis, unsigned int reg,
int __adis_read_reg(struct adis *adis, unsigned int reg,
unsigned int *val, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
@ -138,7 +145,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
@ -146,7 +154,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
@ -155,18 +164,19 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
.cs_change_delay.value = adis->data->cs_change_delay,
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.rx_buf = adis->rx + 2,
.bits_per_word = 8,
.len = 2,
.delay_usecs = adis->data->read_delay,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
},
};
mutex_lock(&adis->txrx_lock);
spi_message_init(&msg);
if (adis->current_page != page) {
@ -188,15 +198,14 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
spi_message_add_tail(&xfers[3], &msg);
break;
default:
ret = -EINVAL;
goto out_unlock;
return -EINVAL;
}
ret = spi_sync(adis->spi, &msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
reg, ret);
goto out_unlock;
return ret;
} else {
adis->current_page = page;
}
@ -210,12 +219,9 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
break;
}
out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_read_reg);
EXPORT_SYMBOL_GPL(__adis_read_reg);
#ifdef CONFIG_DEBUG_FS
@ -253,12 +259,16 @@ int adis_enable_irq(struct adis *adis, bool enable)
int ret = 0;
uint16_t msc;
if (adis->data->enable_irq)
return adis->data->enable_irq(adis, enable);
mutex_lock(&adis->state_lock);
ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (adis->data->enable_irq) {
ret = adis->data->enable_irq(adis, enable);
goto out_unlock;
}
ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (ret)
goto error_ret;
goto out_unlock;
msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
@ -267,26 +277,27 @@ int adis_enable_irq(struct adis *adis, bool enable)
else
msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
error_ret:
out_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL(adis_enable_irq);
/**
* adis_check_status() - Check the device for error conditions
* __adis_check_status() - Check the device for error conditions (unlocked)
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int adis_check_status(struct adis *adis)
int __adis_check_status(struct adis *adis)
{
uint16_t status;
int ret;
int i;
ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
ret = __adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
if (ret)
return ret;
@ -304,32 +315,38 @@ int adis_check_status(struct adis *adis)
return -EIO;
}
EXPORT_SYMBOL_GPL(adis_check_status);
EXPORT_SYMBOL_GPL(__adis_check_status);
/**
* adis_reset() - Reset the device
* __adis_reset() - Reset the device (unlocked version)
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int adis_reset(struct adis *adis)
int __adis_reset(struct adis *adis)
{
int ret;
const struct adis_timeout *timeouts = adis->data->timeouts;
ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg,
ADIS_GLOB_CMD_SW_RESET);
if (ret)
if (ret) {
dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
return ret;
}
return ret;
msleep(timeouts->sw_reset_ms);
return 0;
}
EXPORT_SYMBOL_GPL(adis_reset);
EXPORT_SYMBOL_GPL(__adis_reset);
static int adis_self_test(struct adis *adis)
{
int ret;
const struct adis_timeout *timeouts = adis->data->timeouts;
ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
adis->data->self_test_mask);
if (ret) {
dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
@ -337,12 +354,12 @@ static int adis_self_test(struct adis *adis)
return ret;
}
msleep(adis->data->startup_delay);
msleep(timeouts->self_test_ms);
ret = adis_check_status(adis);
ret = __adis_check_status(adis);
if (adis->data->self_test_no_autoclear)
adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
__adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
return ret;
}
@ -360,19 +377,22 @@ int adis_initial_startup(struct adis *adis)
{
int ret;
mutex_lock(&adis->state_lock);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
adis_reset(adis);
msleep(adis->data->startup_delay);
__adis_reset(adis);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
return ret;
goto out_unlock;
}
}
return 0;
out_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_initial_startup);
@ -398,15 +418,15 @@ int adis_single_conversion(struct iio_dev *indio_dev,
unsigned int uval;
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&adis->state_lock);
ret = adis_read_reg(adis, chan->address, &uval,
ret = __adis_read_reg(adis, chan->address, &uval,
chan->scan_type.storagebits / 8);
if (ret)
goto err_unlock;
if (uval & error_mask) {
ret = adis_check_status(adis);
ret = __adis_check_status(adis);
if (ret)
goto err_unlock;
}
@ -418,7 +438,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
ret = IIO_VAL_INT;
err_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_single_conversion);
@ -438,7 +458,12 @@ EXPORT_SYMBOL_GPL(adis_single_conversion);
int adis_init(struct adis *adis, struct iio_dev *indio_dev,
struct spi_device *spi, const struct adis_data *data)
{
mutex_init(&adis->txrx_lock);
if (!data || !data->timeouts) {
dev_err(&spi->dev, "No config data or timeouts not defined!\n");
return -EINVAL;
}
mutex_init(&adis->state_lock);
adis->spi = spi;
adis->data = data;
iio_device_set_drvdata(indio_dev, adis);

View File

@ -156,12 +156,14 @@ struct adis16400_state;
struct adis16400_chip_info {
const struct iio_chan_spec *channels;
const struct adis_timeout *timeouts;
const int num_channels;
const long flags;
unsigned int gyro_scale_micro;
unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
/* set_freq() & get_freq() need to avoid using ADIS lib's state lock */
int (*set_freq)(struct adis16400_state *st, unsigned int freq);
int (*get_freq)(struct adis16400_state *st);
};
@ -326,7 +328,7 @@ static int adis16334_get_freq(struct adis16400_state *st)
int ret;
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret)
return ret;
@ -350,7 +352,7 @@ static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq)
t <<= ADIS16334_RATE_DIV_SHIFT;
t |= ADIS16334_RATE_INT_CLK;
return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
return __adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
}
static int adis16400_get_freq(struct adis16400_state *st)
@ -358,7 +360,7 @@ static int adis16400_get_freq(struct adis16400_state *st)
int sps, ret;
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret)
return ret;
@ -390,7 +392,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
else
st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
return __adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
}
static const unsigned int adis16400_3db_divisors[] = {
@ -404,7 +406,7 @@ static const unsigned int adis16400_3db_divisors[] = {
[7] = 200, /* Not a valid setting */
};
static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
static int __adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
{
struct adis16400_state *st = iio_priv(indio_dev);
uint16_t val16;
@ -415,11 +417,11 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
break;
}
ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
if (ret)
return ret;
ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
ret = __adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
(val16 & ~0x07) | i);
return ret;
}
@ -507,32 +509,31 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
struct mutex *slock = &st->adis.state_lock;
int ret, sps;
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
mutex_lock(&indio_dev->mlock);
ret = adis_write_reg_16(&st->adis,
adis16400_addresses[chan->scan_index], val);
mutex_unlock(&indio_dev->mlock);
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
/*
* Need to cache values so we can update if the frequency
* changes.
*/
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
st->filt_int = val;
/* Work out update to current value */
sps = st->variant->get_freq(st);
if (sps < 0) {
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return sps;
}
ret = adis16400_set_filter(indio_dev, sps,
ret = __adis16400_set_filter(indio_dev, sps,
val * 1000 + val2 / 1000);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
sps = val * 1000 + val2 / 1000;
@ -540,9 +541,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
if (sps <= 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
ret = st->variant->set_freq(st, sps);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret;
default:
return -EINVAL;
@ -553,6 +554,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
struct mutex *slock = &st->adis.state_lock;
int16_t val16;
int ret;
@ -596,10 +598,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_CALIBBIAS:
mutex_lock(&indio_dev->mlock);
ret = adis_read_reg_16(&st->adis,
adis16400_addresses[chan->scan_index], &val16);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
val16 = sign_extend32(val16, 11);
@ -610,27 +610,27 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val = st->variant->temp_offset;
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
/* Need both the number of taps and the sampling frequency */
ret = adis_read_reg_16(&st->adis,
ret = __adis_read_reg_16(&st->adis,
ADIS16400_SENS_AVG,
&val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret;
}
ret = st->variant->get_freq(st);
if (ret >= 0) {
ret /= adis16400_3db_divisors[val16 & 0x07];
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
}
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
if (ret)
return ret;
ret /= adis16400_3db_divisors[val16 & 0x07];
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(slock);
ret = st->variant->get_freq(st);
mutex_unlock(slock);
if (ret)
return ret;
*val = ret / 1000;
@ -930,6 +930,36 @@ static const struct iio_chan_spec adis16334_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
static const struct adis_timeout adis16300_timeouts = {
.reset_ms = ADIS16400_STARTUP_DELAY,
.sw_reset_ms = ADIS16400_STARTUP_DELAY,
.self_test_ms = ADIS16400_STARTUP_DELAY,
};
static const struct adis_timeout adis16362_timeouts = {
.reset_ms = 130,
.sw_reset_ms = 130,
.self_test_ms = 12,
};
static const struct adis_timeout adis16400_timeouts = {
.reset_ms = 170,
.sw_reset_ms = 170,
.self_test_ms = 12,
};
static const struct adis_timeout adis16445_timeouts = {
.reset_ms = 55,
.sw_reset_ms = 55,
.self_test_ms = 16,
};
static const struct adis_timeout adis16448_timeouts = {
.reset_ms = 90,
.sw_reset_ms = 90,
.self_test_ms = 45,
};
static struct adis16400_chip_info adis16400_chips[] = {
[ADIS16300] = {
.channels = adis16300_channels,
@ -942,6 +972,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16300_timeouts,
},
[ADIS16334] = {
.channels = adis16334_channels,
@ -965,6 +996,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16300_timeouts,
},
[ADIS16360] = {
.channels = adis16350_channels,
@ -977,6 +1009,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16300_timeouts,
},
[ADIS16362] = {
.channels = adis16350_channels,
@ -989,6 +1022,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16362_timeouts,
},
[ADIS16364] = {
.channels = adis16350_channels,
@ -1001,6 +1035,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16362_timeouts,
},
[ADIS16367] = {
.channels = adis16350_channels,
@ -1013,6 +1048,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16300_timeouts,
},
[ADIS16400] = {
.channels = adis16400_channels,
@ -1024,6 +1060,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
.timeouts = &adis16400_timeouts,
},
[ADIS16445] = {
.channels = adis16445_channels,
@ -1037,6 +1074,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
.set_freq = adis16334_set_freq,
.get_freq = adis16334_get_freq,
.timeouts = &adis16445_timeouts,
},
[ADIS16448] = {
.channels = adis16448_channels,
@ -1050,6 +1088,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
.set_freq = adis16334_set_freq,
.get_freq = adis16334_get_freq,
.timeouts = &adis16448_timeouts,
}
};
@ -1087,7 +1126,6 @@ static const struct adis_data adis16400_data = {
.write_delay = 50,
.self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST,
.startup_delay = ADIS16400_STARTUP_DELAY,
.status_error_msgs = adis16400_status_error_msgs,
.status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) |
@ -1121,11 +1159,28 @@ static void adis16400_setup_chan_mask(struct adis16400_state *st)
}
}
static struct adis_data *adis16400_adis_data_alloc(struct adis16400_state *st,
struct device *dev)
{
struct adis_data *data;
data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
memcpy(data, &adis16400_data, sizeof(*data));
data->timeouts = st->variant->timeouts;
return data;
}
static int adis16400_probe(struct spi_device *spi)
{
struct adis16400_state *st;
struct iio_dev *indio_dev;
int ret;
const struct adis_data *adis16400_data;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
@ -1152,7 +1207,11 @@ static int adis16400_probe(struct spi_device *spi)
st->adis.burst->extra_len = sizeof(u16);
}
ret = adis_init(&st->adis, indio_dev, spi, &adis16400_data);
adis16400_data = adis16400_adis_data_alloc(st, &spi->dev);
if (IS_ERR(adis16400_data))
return PTR_ERR(adis16400_data);
ret = adis_init(&st->adis, indio_dev, spi, adis16400_data);
if (ret)
return ret;

View File

@ -383,6 +383,12 @@ static const char * const adis16460_status_error_msgs[] = {
[ADIS16460_DIAG_STAT_FLASH_UPT] = "Flash update failure",
};
static const struct adis_timeout adis16460_timeouts = {
.reset_ms = 225,
.sw_reset_ms = 225,
.self_test_ms = 10,
};
static const struct adis_data adis16460_data = {
.diag_stat_reg = ADIS16460_REG_DIAG_STAT,
.glob_cmd_reg = ADIS16460_REG_GLOB_CMD,
@ -398,6 +404,7 @@ static const struct adis_data adis16460_data = {
BIT(ADIS16460_DIAG_STAT_SPI_COMM) |
BIT(ADIS16460_DIAG_STAT_FLASH_UPT),
.enable_irq = adis16460_enable_irq,
.timeouts = &adis16460_timeouts,
};
static int adis16460_probe(struct spi_device *spi)

View File

@ -138,6 +138,7 @@ struct adis16480_chip_info {
unsigned int max_dec_rate;
const unsigned int *filter_freqs;
bool has_pps_clk_mode;
const struct adis_timeout *timeouts;
};
enum adis16480_int_pin {
@ -555,6 +556,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int freq)
{
struct adis16480 *st = iio_priv(indio_dev);
struct mutex *slock = &st->adis.state_lock;
unsigned int enable_mask, offset, reg;
unsigned int diff, best_diff;
unsigned int i, best_freq;
@ -565,9 +567,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
ret = adis_read_reg_16(&st->adis, reg, &val);
mutex_lock(slock);
ret = __adis_read_reg_16(&st->adis, reg, &val);
if (ret)
return ret;
goto out_unlock;
if (freq == 0) {
val &= ~enable_mask;
@ -589,7 +593,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
val |= enable_mask;
}
return adis_write_reg_16(&st->adis, reg, val);
ret = __adis_write_reg_16(&st->adis, reg, val);
out_unlock:
mutex_unlock(slock);
return ret;
}
static int adis16480_read_raw(struct iio_dev *indio_dev,
@ -779,6 +787,7 @@ enum adis16480_variant {
ADIS16480,
ADIS16485,
ADIS16488,
ADIS16490,
ADIS16495_1,
ADIS16495_2,
ADIS16495_3,
@ -787,6 +796,30 @@ enum adis16480_variant {
ADIS16497_3,
};
static const struct adis_timeout adis16485_timeouts = {
.reset_ms = 560,
.sw_reset_ms = 120,
.self_test_ms = 12,
};
static const struct adis_timeout adis16480_timeouts = {
.reset_ms = 560,
.sw_reset_ms = 560,
.self_test_ms = 12,
};
static const struct adis_timeout adis16495_timeouts = {
.reset_ms = 170,
.sw_reset_ms = 130,
.self_test_ms = 40,
};
static const struct adis_timeout adis16495_1_timeouts = {
.reset_ms = 250,
.sw_reset_ms = 210,
.self_test_ms = 20,
};
static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
@ -805,6 +838,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
.timeouts = &adis16485_timeouts,
},
[ADIS16480] = {
.channels = adis16480_channels,
@ -817,6 +851,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
.timeouts = &adis16480_timeouts,
},
[ADIS16485] = {
.channels = adis16485_channels,
@ -829,6 +864,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
.timeouts = &adis16485_timeouts,
},
[ADIS16488] = {
.channels = adis16480_channels,
@ -841,6 +877,21 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.int_clk = 2460000,
.max_dec_rate = 2048,
.filter_freqs = adis16480_def_filter_freqs,
.timeouts = &adis16485_timeouts,
},
[ADIS16490] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
.gyro_max_val = 20000 << 16,
.gyro_max_scale = IIO_DEGREE_TO_RAD(100),
.accel_max_val = IIO_M_S_2_TO_G(16000 << 16),
.accel_max_scale = 8,
.temp_scale = 14285, /* 14.285 milli degree Celsius */
.int_clk = 4250000,
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_timeouts,
},
[ADIS16495_1] = {
.channels = adis16485_channels,
@ -854,6 +905,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_1_timeouts,
},
[ADIS16495_2] = {
.channels = adis16485_channels,
@ -867,6 +919,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_1_timeouts,
},
[ADIS16495_3] = {
.channels = adis16485_channels,
@ -880,6 +933,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_1_timeouts,
},
[ADIS16497_1] = {
.channels = adis16485_channels,
@ -893,6 +947,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_1_timeouts,
},
[ADIS16497_2] = {
.channels = adis16485_channels,
@ -906,6 +961,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_1_timeouts,
},
[ADIS16497_3] = {
.channels = adis16485_channels,
@ -919,6 +975,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
.max_dec_rate = 4250,
.filter_freqs = adis16495_def_filter_freqs,
.has_pps_clk_mode = true,
.timeouts = &adis16495_1_timeouts,
},
};
@ -947,14 +1004,14 @@ static int adis16480_enable_irq(struct adis *adis, bool enable)
uint16_t val;
int ret;
ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
if (ret)
return ret;
val &= ~ADIS16480_DRDY_EN_MSK;
val |= ADIS16480_DRDY_EN(enable);
return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
}
static int adis16480_initial_setup(struct iio_dev *indio_dev)
@ -1188,9 +1245,26 @@ static int adis16480_get_ext_clocks(struct adis16480 *st)
return 0;
}
static struct adis_data *adis16480_adis_data_alloc(struct adis16480 *st,
struct device *dev)
{
struct adis_data *data;
data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
memcpy(data, &adis16480_data, sizeof(*data));
data->timeouts = st->chip_info->timeouts;
return data;
}
static int adis16480_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
const struct adis_data *adis16480_data;
struct iio_dev *indio_dev;
struct adis16480 *st;
int ret;
@ -1211,7 +1285,11 @@ static int adis16480_probe(struct spi_device *spi)
indio_dev->info = &adis16480_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data);
adis16480_data = adis16480_adis_data_alloc(st, &spi->dev);
if (IS_ERR(adis16480_data))
return PTR_ERR(adis16480_data);
ret = adis_init(&st->adis, indio_dev, spi, adis16480_data);
if (ret)
return ret;
@ -1278,6 +1356,7 @@ static const struct spi_device_id adis16480_ids[] = {
{ "adis16480", ADIS16480 },
{ "adis16485", ADIS16485 },
{ "adis16488", ADIS16488 },
{ "adis16490", ADIS16490 },
{ "adis16495-1", ADIS16495_1 },
{ "adis16495-2", ADIS16495_2 },
{ "adis16495-3", ADIS16495_3 },
@ -1293,6 +1372,7 @@ static const struct of_device_id adis16480_of_match[] = {
{ .compatible = "adi,adis16480" },
{ .compatible = "adi,adis16485" },
{ .compatible = "adi,adis16488" },
{ .compatible = "adi,adis16490" },
{ .compatible = "adi,adis16495-1" },
{ .compatible = "adi,adis16495-2" },
{ .compatible = "adi,adis16495-3" },

View File

@ -129,7 +129,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
return -ENOMEM;
if (adis->data->has_paging) {
mutex_lock(&adis->txrx_lock);
mutex_lock(&adis->state_lock);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
@ -144,7 +144,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
if (adis->data->has_paging) {
adis->current_page = 0;
mutex_unlock(&adis->txrx_lock);
mutex_unlock(&adis->state_lock);
}
iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer,

View File

@ -10,11 +10,12 @@ config INV_MPU6050_IIO
config INV_MPU6050_I2C
tristate "Invensense MPU6050 devices (I2C)"
depends on I2C_MUX
depends on I2C
select I2C_MUX
select INV_MPU6050_IIO
select REGMAP_I2C
help
This driver supports the Invensense MPU6000/6050/6500/6515,
This driver supports the Invensense MPU6050/6500/6515,
MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
over I2C.
This driver can be built as a module. The module will be called
@ -26,8 +27,8 @@ config INV_MPU6050_SPI
select INV_MPU6050_IIO
select REGMAP_SPI
help
This driver supports the Invensense MPU6000/6050/6500/6515,
MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
This driver supports the Invensense MPU6000/6500/6515,
MPU9250/9255 and ICM20608/20602 motion tracking devices
over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.

View File

@ -104,6 +104,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
.divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE),
.gyro_fifo_enable = false,
.accl_fifo_enable = false,
.temp_fifo_enable = false,
.magn_fifo_enable = false,
.accl_fs = INV_MPU6050_FS_02G,
.user_ctrl = 0,
@ -856,19 +857,27 @@ static const struct iio_chan_spec_ext_info inv_ext_info[] = {
.ext_info = inv_ext_info, \
}
#define INV_MPU6050_TEMP_CHAN(_index) \
{ \
.type = IIO_TEMP, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
| BIT(IIO_CHAN_INFO_OFFSET) \
| BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = _index, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.shift = 0, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec inv_mpu_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP),
/*
* Note that temperature should only be via polled reading only,
* not the final scan elements output.
*/
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
| BIT(IIO_CHAN_INFO_OFFSET)
| BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1,
},
INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
@ -878,22 +887,29 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
};
#define INV_MPU6050_SCAN_MASK_3AXIS_ACCEL \
(BIT(INV_MPU6050_SCAN_ACCL_X) \
| BIT(INV_MPU6050_SCAN_ACCL_Y) \
| BIT(INV_MPU6050_SCAN_ACCL_Z))
#define INV_MPU6050_SCAN_MASK_3AXIS_GYRO \
(BIT(INV_MPU6050_SCAN_GYRO_X) \
| BIT(INV_MPU6050_SCAN_GYRO_Y) \
| BIT(INV_MPU6050_SCAN_GYRO_Z))
#define INV_MPU6050_SCAN_MASK_TEMP (BIT(INV_MPU6050_SCAN_TEMP))
static const unsigned long inv_mpu_scan_masks[] = {
/* 3-axis accel */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL,
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_TEMP,
/* 3-axis gyro */
BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_SCAN_MASK_3AXIS_GYRO,
INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU6050_SCAN_MASK_TEMP,
/* 6-axis accel + gyro */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO,
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO
| INV_MPU6050_SCAN_MASK_TEMP,
0,
};
@ -915,19 +931,30 @@ static const unsigned long inv_mpu_scan_masks[] = {
.ext_info = inv_ext_info, \
}
static const struct iio_chan_spec inv_mpu9150_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
/* Magnetometer resolution is 13 bits */
INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 13, INV_MPU9X50_SCAN_MAGN_X),
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 13, INV_MPU9X50_SCAN_MAGN_Y),
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 13, INV_MPU9X50_SCAN_MAGN_Z),
};
static const struct iio_chan_spec inv_mpu9250_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
/*
* Note that temperature should only be via polled reading only,
* not the final scan elements output.
*/
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
| BIT(IIO_CHAN_INFO_OFFSET)
| BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1,
},
INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
@ -942,98 +969,50 @@ static const struct iio_chan_spec inv_mpu9250_channels[] = {
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z),
};
#define INV_MPU9X50_SCAN_MASK_3AXIS_MAGN \
(BIT(INV_MPU9X50_SCAN_MAGN_X) \
| BIT(INV_MPU9X50_SCAN_MAGN_Y) \
| BIT(INV_MPU9X50_SCAN_MAGN_Z))
static const unsigned long inv_mpu9x50_scan_masks[] = {
/* 3-axis accel */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL,
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_TEMP,
/* 3-axis gyro */
BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_SCAN_MASK_3AXIS_GYRO,
INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU6050_SCAN_MASK_TEMP,
/* 3-axis magn */
BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
INV_MPU9X50_SCAN_MASK_3AXIS_MAGN,
INV_MPU9X50_SCAN_MASK_3AXIS_MAGN | INV_MPU6050_SCAN_MASK_TEMP,
/* 6-axis accel + gyro */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO,
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO
| INV_MPU6050_SCAN_MASK_TEMP,
/* 6-axis accel + magn */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN,
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN
| INV_MPU6050_SCAN_MASK_TEMP,
/* 6-axis gyro + magn */
BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z)
| BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN,
INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN
| INV_MPU6050_SCAN_MASK_TEMP,
/* 9-axis accel + gyro + magn */
BIT(INV_MPU6050_SCAN_ACCL_X)
| BIT(INV_MPU6050_SCAN_ACCL_Y)
| BIT(INV_MPU6050_SCAN_ACCL_Z)
| BIT(INV_MPU6050_SCAN_GYRO_X)
| BIT(INV_MPU6050_SCAN_GYRO_Y)
| BIT(INV_MPU6050_SCAN_GYRO_Z)
| BIT(INV_MPU9X50_SCAN_MAGN_X)
| BIT(INV_MPU9X50_SCAN_MAGN_Y)
| BIT(INV_MPU9X50_SCAN_MAGN_Z),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO
| INV_MPU9X50_SCAN_MASK_3AXIS_MAGN,
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO
| INV_MPU9X50_SCAN_MASK_3AXIS_MAGN
| INV_MPU6050_SCAN_MASK_TEMP,
0,
};
static const struct iio_chan_spec inv_icm20602_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
| BIT(IIO_CHAN_INFO_OFFSET)
| BIT(IIO_CHAN_INFO_SCALE),
.scan_index = INV_ICM20602_SCAN_TEMP,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_ICM20602_SCAN_ACCL_X),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_ICM20602_SCAN_ACCL_Z),
};
static const unsigned long inv_icm20602_scan_masks[] = {
/* 3-axis accel + temp (mandatory) */
BIT(INV_ICM20602_SCAN_ACCL_X)
| BIT(INV_ICM20602_SCAN_ACCL_Y)
| BIT(INV_ICM20602_SCAN_ACCL_Z)
| BIT(INV_ICM20602_SCAN_TEMP),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_TEMP,
/* 3-axis gyro + temp (mandatory) */
BIT(INV_ICM20602_SCAN_GYRO_X)
| BIT(INV_ICM20602_SCAN_GYRO_Y)
| BIT(INV_ICM20602_SCAN_GYRO_Z)
| BIT(INV_ICM20602_SCAN_TEMP),
INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU6050_SCAN_MASK_TEMP,
/* 6-axis accel + gyro + temp (mandatory) */
BIT(INV_ICM20602_SCAN_ACCL_X)
| BIT(INV_ICM20602_SCAN_ACCL_Y)
| BIT(INV_ICM20602_SCAN_ACCL_Z)
| BIT(INV_ICM20602_SCAN_GYRO_X)
| BIT(INV_ICM20602_SCAN_GYRO_Y)
| BIT(INV_ICM20602_SCAN_GYRO_Z)
| BIT(INV_ICM20602_SCAN_TEMP),
INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO
| INV_MPU6050_SCAN_MASK_TEMP,
0,
};
@ -1241,7 +1220,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
irq_type = irqd_get_trigger_type(desc);
if (!irq_type)
irq_type = IRQF_TRIGGER_RISING;
if (irq_type == IRQF_TRIGGER_RISING)
if (irq_type & IRQF_TRIGGER_RISING) // rising or both-edge
st->irq_mask = INV_MPU6050_ACTIVE_HIGH;
else if (irq_type == IRQF_TRIGGER_FALLING)
st->irq_mask = INV_MPU6050_ACTIVE_LOW;
@ -1324,25 +1303,20 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
inv_mpu_bus_setup(indio_dev);
switch (chip_type) {
case INV_MPU9150:
indio_dev->channels = inv_mpu9150_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
break;
case INV_MPU9250:
case INV_MPU9255:
/*
* Use magnetometer inside the chip only if there is no i2c
* auxiliary device in use.
*/
if (!st->magn_disabled) {
indio_dev->channels = inv_mpu9250_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
} else {
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks;
}
indio_dev->channels = inv_mpu9250_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
break;
case INV_ICM20602:
indio_dev->channels = inv_icm20602_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_icm20602_scan_masks;
break;
default:
@ -1351,6 +1325,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
indio_dev->available_scan_masks = inv_mpu_scan_masks;
break;
}
/*
* Use magnetometer inside the chip only if there is no i2c
* auxiliary device in use. Otherwise Going back to 6-axis only.
*/
if (st->magn_disabled) {
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks;
}
indio_dev->info = &mpu_info;
indio_dev->modes = INDIO_BUFFER_TRIGGERED;

View File

@ -77,6 +77,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev)
case INV_ICM20602:
/* no i2c auxiliary bus on the chip */
return false;
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
if (st->magn_disabled)
@ -102,6 +103,7 @@ static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
struct device_node *mux_node;
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
mux_node = of_get_child_by_name(dev->of_node, "i2c-gate");

View File

@ -86,6 +86,7 @@ enum inv_devices {
* @accl_fs: accel full scale range.
* @accl_fifo_enable: enable accel data output
* @gyro_fifo_enable: enable gyro data output
* @temp_fifo_enable: enable temp data output
* @magn_fifo_enable: enable magn data output
* @divider: chip sample rate divider (sample rate divider - 1)
*/
@ -95,6 +96,7 @@ struct inv_mpu6050_chip_config {
unsigned int accl_fs:2;
unsigned int accl_fifo_enable:1;
unsigned int gyro_fifo_enable:1;
unsigned int temp_fifo_enable:1;
unsigned int magn_fifo_enable:1;
u8 divider;
u8 user_ctrl;
@ -184,6 +186,7 @@ struct inv_mpu6050_state {
#define INV_MPU6050_BIT_SLAVE_2 0x04
#define INV_MPU6050_BIT_ACCEL_OUT 0x08
#define INV_MPU6050_BITS_GYRO_OUT 0x70
#define INV_MPU6050_BIT_TEMP_OUT 0x80
#define INV_MPU6050_REG_I2C_MST_CTRL 0x24
#define INV_MPU6050_BITS_I2C_MST_CLK_400KHZ 0x0D
@ -268,8 +271,8 @@ struct inv_mpu6050_state {
/* MPU9X50 9-axis magnetometer */
#define INV_MPU9X50_BYTES_MAGN 7
/* ICM20602 FIFO samples include temperature readings */
#define INV_ICM20602_BYTES_PER_TEMP_SENSOR 2
/* FIFO temperature sample size */
#define INV_MPU6050_BYTES_PER_TEMP_SENSOR 2
/* mpu6500 registers */
#define INV_MPU6500_REG_ACCEL_CONFIG_2 0x1D
@ -298,7 +301,7 @@ struct inv_mpu6050_state {
#define INV_ICM20608_TEMP_OFFSET 8170
#define INV_ICM20608_TEMP_SCALE 3059976
/* 6 + 6 + 7 (for MPU9x50) = 19 round up to 24 and plus 8 */
/* 6 + 6 + 2 + 7 (for MPU9x50) = 21 round up to 24 and plus 8 */
#define INV_MPU6050_OUTPUT_DATA_SIZE 32
#define INV_MPU6050_REG_INT_PIN_CFG 0x37
@ -344,6 +347,7 @@ enum inv_mpu6050_scan {
INV_MPU6050_SCAN_ACCL_X,
INV_MPU6050_SCAN_ACCL_Y,
INV_MPU6050_SCAN_ACCL_Z,
INV_MPU6050_SCAN_TEMP,
INV_MPU6050_SCAN_GYRO_X,
INV_MPU6050_SCAN_GYRO_Y,
INV_MPU6050_SCAN_GYRO_Z,
@ -355,18 +359,6 @@ enum inv_mpu6050_scan {
INV_MPU9X50_SCAN_TIMESTAMP,
};
/* scan element definition for ICM20602, which includes temperature */
enum inv_icm20602_scan {
INV_ICM20602_SCAN_ACCL_X,
INV_ICM20602_SCAN_ACCL_Y,
INV_ICM20602_SCAN_ACCL_Z,
INV_ICM20602_SCAN_TEMP,
INV_ICM20602_SCAN_GYRO_X,
INV_ICM20602_SCAN_GYRO_Y,
INV_ICM20602_SCAN_GYRO_Z,
INV_ICM20602_SCAN_TIMESTAMP,
};
enum inv_mpu6050_filter_e {
INV_MPU6050_FILTER_256HZ_NOLPF2 = 0,
INV_MPU6050_FILTER_188HZ,

View File

@ -12,7 +12,9 @@
#include "inv_mpu_magn.h"
/*
* MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus
* MPU9xxx magnetometer are AKM chips on I2C aux bus
* MPU9150 is AK8975
* MPU9250 is AK8963
*/
#define INV_MPU_MAGN_I2C_ADDR 0x0C
@ -33,10 +35,10 @@
#define INV_MPU_MAGN_BITS_MODE_PWDN 0x00
#define INV_MPU_MAGN_BITS_MODE_SINGLE 0x01
#define INV_MPU_MAGN_BITS_MODE_FUSE 0x0F
#define INV_MPU_MAGN_BIT_OUTPUT_BIT 0x10
#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT 0x10
#define INV_MPU_MAGN_REG_CNTL2 0x0B
#define INV_MPU_MAGN_BIT_SRST 0x01
#define INV_MPU9250_MAGN_REG_CNTL2 0x0B
#define INV_MPU9250_MAGN_BIT_SRST 0x01
#define INV_MPU_MAGN_REG_ASAX 0x10
#define INV_MPU_MAGN_REG_ASAY 0x11
@ -48,6 +50,7 @@
static bool inv_magn_supported(const struct inv_mpu6050_state *st)
{
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
return true;
@ -61,6 +64,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
{
uint8_t val;
uint8_t asa[3];
int32_t sensitivity;
int ret;
/* check whoami */
@ -71,12 +75,19 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
if (val != INV_MPU_MAGN_BITS_WIA)
return -ENODEV;
/* reset chip */
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
INV_MPU_MAGN_REG_CNTL2,
INV_MPU_MAGN_BIT_SRST);
if (ret)
return ret;
/* software reset for MPU925x only */
switch (st->chip_type) {
case INV_MPU9250:
case INV_MPU9255:
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
INV_MPU9250_MAGN_REG_CNTL2,
INV_MPU9250_MAGN_BIT_SRST);
if (ret)
return ret;
break;
default:
break;
}
/* read fuse ROM data */
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
@ -97,6 +108,25 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
if (ret)
return ret;
/*
* Sensor sentivity
* 1 uT = 0.01 G and value is in micron (1e6)
* sensitvity = x uT * 0.01 * 1e6
*/
switch (st->chip_type) {
case INV_MPU9150:
/* sensor sensitivity is 0.3 uT */
sensitivity = 3000;
break;
case INV_MPU9250:
case INV_MPU9255:
/* sensor sensitivity in 16 bits mode: 0.15 uT */
sensitivity = 1500;
break;
default:
return -EINVAL;
}
/*
* Sensitivity adjustement and scale to Gauss
*
@ -104,16 +134,11 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
* Factor simplification:
* Hadj = H * ((ASA + 128) / 256)
*
* Sensor sentivity
* 0.15 uT in 16 bits mode
* 1 uT = 0.01 G and value is in micron (1e6)
* sensitvity = 0.15 uT * 0.01 * 1e6
*
* raw_to_gauss = Hadj * 1500
* raw_to_gauss = Hadj * sensitivity
*/
st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256;
st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256;
st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256;
st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * sensitivity) / 256;
st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * sensitivity) / 256;
st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * sensitivity) / 256;
return 0;
}
@ -129,6 +154,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
*/
int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
{
uint8_t val;
int ret;
/* quit if chip is not supported */
@ -179,10 +205,17 @@ int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
if (ret)
return ret;
/* add 16 bits mode */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1),
INV_MPU_MAGN_BITS_MODE_SINGLE |
INV_MPU_MAGN_BIT_OUTPUT_BIT);
/* add 16 bits mode for MPU925x */
val = INV_MPU_MAGN_BITS_MODE_SINGLE;
switch (st->chip_type) {
case INV_MPU9250:
case INV_MPU9255:
val |= INV_MPU9250_MAGN_BIT_OUTPUT_BIT;
break;
default:
break;
}
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), val);
if (ret)
return ret;
@ -237,6 +270,7 @@ int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
/* fill magnetometer orientation */
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
/* x <- y */

View File

@ -142,6 +142,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
d |= INV_MPU6050_BITS_GYRO_OUT;
if (st->chip_config.accl_fifo_enable)
d |= INV_MPU6050_BIT_ACCEL_OUT;
if (st->chip_config.temp_fifo_enable)
d |= INV_MPU6050_BIT_TEMP_OUT;
if (st->chip_config.magn_fifo_enable)
d |= INV_MPU6050_BIT_SLAVE_0;
result = regmap_write(st->map, st->reg->fifo_en, d);
@ -183,11 +185,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
"failed to ack interrupt\n");
goto flush_fifo;
}
if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) {
dev_warn(regmap_get_device(st->map),
"spurious interrupt with status 0x%x\n", int_status);
if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT))
goto end_session;
}
if (!(st->chip_config.accl_fifo_enable |
st->chip_config.gyro_fifo_enable |
@ -200,8 +199,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
if (st->chip_config.gyro_fifo_enable)
bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
if (st->chip_type == INV_ICM20602)
bytes_per_datum += INV_ICM20602_BYTES_PER_TEMP_SENSOR;
if (st->chip_config.temp_fifo_enable)
bytes_per_datum += INV_MPU6050_BYTES_PER_TEMP_SENSOR;
if (st->chip_config.magn_fifo_enable)
bytes_per_datum += INV_MPU9X50_BYTES_MAGN;

View File

@ -74,7 +74,6 @@ static int inv_mpu_probe(struct spi_device *spi)
static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000},
{"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},

View File

@ -24,6 +24,9 @@ static void inv_scan_query_mpu6050(struct iio_dev *indio_dev)
indio_dev->active_scan_mask) ||
test_bit(INV_MPU6050_SCAN_ACCL_Z,
indio_dev->active_scan_mask);
st->chip_config.temp_fifo_enable =
test_bit(INV_MPU6050_SCAN_TEMP, indio_dev->active_scan_mask);
}
static void inv_scan_query_mpu9x50(struct iio_dev *indio_dev)
@ -50,6 +53,7 @@ static void inv_scan_query(struct iio_dev *indio_dev)
struct inv_mpu6050_state *st = iio_priv(indio_dev);
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
return inv_scan_query_mpu9x50(indio_dev);

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