Third set of IIO new device support cleanups and fixes for the 5.5 cycle.

New device support
 * ad5446
   - Support the ad5600 DAC (id only needed).
 * ad7292 ADC DAC etc
   - New driver plus dt-bindings.
 * veml6030 ambient light sensor
   - New driver plus dt-bindings and sysfs docs.
 
 Features
 * mpu6050
   - Explicit VDD control.
 * stm32-adc
   - Allow limiting of max clock frequency from devicetree to ensure it's
     suitable for external circuitry.
 
 yaml binding conversions
 * ltc1660
 * mcp3911
 
 Fixes
 * adis16480
   - Fix wrong scale factors.
   - Fix debugfs reg access by providing the callback.
 * cros_ec_baro
   - Fixing missing mask entry to make available sample frequencies visible
     in sysfs.
 * st_lsm6dsx
   - Explicitly handle different ODR table sizes.
   - Handle restrictions between slave ODR and accel ODR when
     both are enabled.
   - Allow ODR to be expressed more accurately by using miliHz.
 * tools
   - Fix an issue with parallel builds.
 
 Cleanups and warning fixes
 * adis16136, adis16400, adis16460, adis-lib
   - Change some checks on return values to be for 0 rather than strictly
     negative. Avoids some fiddly issues with the compiler concluding some
     variables are initialized due to a mixture of error checks.
   - Assign values only on success of 'read' operations - avoiding any
     chance the compiler will falsly suggest they might be used uninitialized.
   - Whitespace and simlar cleanups.
 * aspeed adc
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * bcm-iproc-adc
   - Stray semicolon removal.
 * cc10001
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * dln2-adc
   - Reorganise the buffered mode setup and tear down. Part of moving towards
     being able to refactor this area of the IIO core.
 * hdc100x
   - Reorganise the buffered mode setup and tear down.
 * ingenic-adc
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * lpc18xx-adc
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * lpc18xx-dac
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * mt6577
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * npcm
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * rcar-gyroadc
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * spear-adc
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * vf610-adc
   - devm_platfom_ioremap_resource to reduce boilerplate.
 * vf610-dac
   - devm_platfom_ioremap_resource to reduce boilerplate.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl3JsAoRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0Foiw0w//Qpe9IxW4kdiMZB0vMr0mz74Aa6niS1Rm
 c/vMEv7x/0cHjNBJWZiI4VQqScadVMMk2nD/KHAMt+9ZgZg+/r9d7PkVsrEIydZw
 XBFf8qwFYoxL6jAgWinuCWuWAE3o9aKVqqGj/aosloUwzZDBXUpmCSnRpBFOhEyp
 hbNNYZJo4Sbrg/xOYqyIaGJFTes0u+n8OuiS53dLN71lGW6BbGyJQtPzb/7rkOV/
 z7zL0nbIfXszRrFQc17eBlblZvWl3QtHY08aiem8gcTkQbzTOTVWgLxyg+aZwBB2
 XkCeeI21gLjVh2rxAcqBTs7OWObyGUjVES0+fAGBqIGEslq9nruMPrVrlTqkUHxJ
 +vMPPA2VqvAqLI6cBz8oG9HsO/TUTQaRV3tHMF5WnoX9mDEzu9A8V4Cd7pg15lc1
 aEvDXq5UU+aocKOofvyZJ8LqBi0ZmxJpohMGHHyDPmdtlL/HuWWsn9FyzsSgdBuc
 EiGH+GKlUnG4mNOibr2L+TOBZwyelL+wGu40Xld3+KTyHyaysvQ2puP6wHTVf1da
 ME0e6sFDPk4k+JTmsT9vYljgEfW3IMuTzI0BePlsfsx3/SbMZqdYLkijIHM1mpyE
 yhaP/00u4aDFOlE1Ct0iwakUJ4Myxw0UeOz6deNKdTHcOExy28c8AIG6dqZhAJ9S
 ohWETBDIDzI=
 =ckQz
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-5.5c' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

Third set of IIO new device support cleanups and fixes for the 5.5 cycle.

New device support
* ad5446
  - Support the ad5600 DAC (id only needed).
* ad7292 ADC DAC etc
  - New driver plus dt-bindings.
* veml6030 ambient light sensor
  - New driver plus dt-bindings and sysfs docs.

Features
* mpu6050
  - Explicit VDD control.
* stm32-adc
  - Allow limiting of max clock frequency from devicetree to ensure it's
    suitable for external circuitry.

yaml binding conversions
* ltc1660
* mcp3911

Fixes
* adis16480
  - Fix wrong scale factors.
  - Fix debugfs reg access by providing the callback.
* cros_ec_baro
  - Fixing missing mask entry to make available sample frequencies visible
    in sysfs.
* st_lsm6dsx
  - Explicitly handle different ODR table sizes.
  - Handle restrictions between slave ODR and accel ODR when
    both are enabled.
  - Allow ODR to be expressed more accurately by using miliHz.
* tools
  - Fix an issue with parallel builds.

Cleanups and warning fixes
* adis16136, adis16400, adis16460, adis-lib
  - Change some checks on return values to be for 0 rather than strictly
    negative. Avoids some fiddly issues with the compiler concluding some
    variables are initialized due to a mixture of error checks.
  - Assign values only on success of 'read' operations - avoiding any
    chance the compiler will falsly suggest they might be used uninitialized.
  - Whitespace and simlar cleanups.
* aspeed adc
  - devm_platfom_ioremap_resource to reduce boilerplate.
* bcm-iproc-adc
  - Stray semicolon removal.
* cc10001
  - devm_platfom_ioremap_resource to reduce boilerplate.
* dln2-adc
  - Reorganise the buffered mode setup and tear down. Part of moving towards
    being able to refactor this area of the IIO core.
* hdc100x
  - Reorganise the buffered mode setup and tear down.
* ingenic-adc
  - devm_platfom_ioremap_resource to reduce boilerplate.
* lpc18xx-adc
  - devm_platfom_ioremap_resource to reduce boilerplate.
* lpc18xx-dac
  - devm_platfom_ioremap_resource to reduce boilerplate.
* mt6577
  - devm_platfom_ioremap_resource to reduce boilerplate.
* npcm
  - devm_platfom_ioremap_resource to reduce boilerplate.
* rcar-gyroadc
  - devm_platfom_ioremap_resource to reduce boilerplate.
* spear-adc
  - devm_platfom_ioremap_resource to reduce boilerplate.
* vf610-adc
  - devm_platfom_ioremap_resource to reduce boilerplate.
* vf610-dac
  - devm_platfom_ioremap_resource to reduce boilerplate.

* tag 'iio-for-5.5c' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (43 commits)
  iio: adis16480: Add debugfs_reg_access entry
  iio: adis16480: Fix scales factors
  tools: iio: Correctly add make dependency for iio_utils
  iio: adc: Add driver support for AD7292
  dt-bindings: iio: adc: Add dt-schema for AD7292
  dt-bindings: iio: adc: Migrate MCP3911 documentation to yaml
  iio: imu: mpu6050: Add support for vdd-supply regulator
  dt-bindings: iio: imu: mpu6050: add vdd-supply
  iio: cros_ec_baro: set info_mask_shared_by_all_available field
  iio: dac: ad5446: Add support for new AD5600 DAC
  dt-bindings: iio: dac: Migrate LTC1660 documentation to yaml
  iio: documentation: light: Add veml6030 sysfs documentation
  dt-bindings: iio: light: add veml6030 ALS bindings
  iio: light: add driver for veml6030 ambient light sensor
  iio: imu: st_lsm6dsx: express odr in mHZ
  iio: imu: st_lsm6dsx: fix ODR check in st_lsm6dsx_write_raw
  iio: imu: st_lsm6dsx: explicitly define odr table size
  iio: adc: stm32: allow to tune analog clock
  dt-bindings: iio: stm32-adc: add max clock rate property
  iio: dac: vf610: Use devm_platform_ioremap_resource
  ...
This commit is contained in:
Greg Kroah-Hartman 2019-11-13 19:24:42 +08:00
Родитель 6366e523eb 4c35b7a51e
Коммит 8bde9f3d2a
48 изменённых файлов: 1955 добавлений и 339 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -901,6 +901,14 @@ S: Supported
F: drivers/iio/adc/ad7124.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
ANALOG DEVICES INC AD7292 DRIVER
M: Marcelo Schmitt <marcelo.schmitt1@gmail.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7292.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7292.yaml
ANALOG DEVICES INC AD7606 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
M: Beniamin Bia <beniamin.bia@analog.com>
@ -9622,7 +9630,7 @@ LTC1660 DAC DRIVER
M: Marcus Folkesson <marcus.folkesson@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/dac/ltc1660.txt
F: Documentation/devicetree/bindings/iio/dac/lltc,ltc1660.yaml
F: drivers/iio/dac/ltc1660.c
LTC2983 IIO TEMPERATURE DRIVER
@ -10738,7 +10746,7 @@ M: Kent Gustavsson <kent@minoris.se>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/adc/mcp3911.c
F: Documentation/devicetree/bindings/iio/adc/mcp3911.txt
F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml
MICROCHIP NAND DRIVER
M: Tudor Ambarus <tudor.ambarus@microchip.com>

Просмотреть файл

@ -55,6 +55,16 @@ config AD7291
To compile this driver as a module, choose M here: the
module will be called ad7291.
config AD7292
tristate "Analog Devices AD7292 ADC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD7292
8 Channel ADC with temperature sensor.
To compile this driver as a module, choose M here: the
module will be called ad7292.
config AD7298
tristate "Analog Devices AD7298 ADC driver"
depends on SPI

Просмотреть файл

@ -9,6 +9,7 @@ obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o

350
drivers/iio/adc/ad7292.c Normal file
Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -428,7 +428,6 @@ static int ingenic_adc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct iio_dev *iio_dev;
struct ingenic_adc *adc;
struct resource *mem_base;
const struct ingenic_adc_soc_data *soc_data;
int ret;
@ -445,8 +444,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
mutex_init(&adc->aux_lock);
adc->soc_data = soc_data;
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(dev, mem_base);
adc->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(adc->base))
return PTR_ERR(adc->base);

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -79,6 +79,7 @@ struct stm32_adc_priv_cfg {
* @domain: irq domain reference
* @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
* @max_clk_rate: desired maximum clock rate
* @booster: booster supply reference
* @vdd: vdd supply reference
* @vdda: vdda analog supply reference
@ -95,6 +96,7 @@ struct stm32_adc_priv {
struct irq_domain *domain;
struct clk *aclk;
struct clk *bclk;
u32 max_clk_rate;
struct regulator *booster;
struct regulator *vdd;
struct regulator *vdda;
@ -141,7 +143,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev,
}
for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) {
if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz)
if ((rate / stm32f4_pclk_div[i]) <= priv->max_clk_rate)
break;
}
if (i >= ARRAY_SIZE(stm32f4_pclk_div)) {
@ -230,7 +232,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (ckmode)
continue;
if ((rate / div) <= priv->cfg->max_clk_rate_hz)
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
}
@ -250,7 +252,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (!ckmode)
continue;
if ((rate / div) <= priv->cfg->max_clk_rate_hz)
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
@ -655,6 +657,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct resource *res;
u32 max_rate;
int ret;
if (!pdev->dev.of_node)
@ -731,6 +734,13 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->common.vref_mv = ret / 1000;
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
ret = of_property_read_u32(pdev->dev.of_node, "st,max-clk-rate-hz",
&max_rate);
if (!ret)
priv->max_clk_rate = min(max_rate, priv->cfg->max_clk_rate_hz);
else
priv->max_clk_rate = priv->cfg->max_clk_rate_hz;
ret = priv->cfg->clk_sel(pdev, priv);
if (ret < 0)
goto err_hw_stop;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -1149,14 +1149,14 @@ error_power_off:
return result;
}
static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
static int inv_mpu_core_enable_regulator_vddio(struct inv_mpu6050_state *st)
{
int result;
result = regulator_enable(st->vddio_supply);
if (result) {
dev_err(regmap_get_device(st->map),
"Failed to enable regulator: %d\n", result);
"Failed to enable vddio regulator: %d\n", result);
} else {
/* Give the device a little bit of time to start up. */
usleep_range(35000, 70000);
@ -1165,21 +1165,29 @@ static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
return result;
}
static int inv_mpu_core_disable_regulator(struct inv_mpu6050_state *st)
static int inv_mpu_core_disable_regulator_vddio(struct inv_mpu6050_state *st)
{
int result;
result = regulator_disable(st->vddio_supply);
if (result)
dev_err(regmap_get_device(st->map),
"Failed to disable regulator: %d\n", result);
"Failed to disable vddio regulator: %d\n", result);
return result;
}
static void inv_mpu_core_disable_regulator_action(void *_data)
{
inv_mpu_core_disable_regulator(_data);
struct inv_mpu6050_state *st = _data;
int result;
result = regulator_disable(st->vdd_supply);
if (result)
dev_err(regmap_get_device(st->map),
"Failed to disable vdd regulator: %d\n", result);
inv_mpu_core_disable_regulator_vddio(st);
}
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
@ -1248,6 +1256,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return -EINVAL;
}
st->vdd_supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(st->vdd_supply)) {
if (PTR_ERR(st->vdd_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vdd regulator %d\n",
(int)PTR_ERR(st->vdd_supply));
return PTR_ERR(st->vdd_supply);
}
st->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(st->vddio_supply)) {
if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
@ -1257,9 +1274,17 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return PTR_ERR(st->vddio_supply);
}
result = inv_mpu_core_enable_regulator(st);
if (result)
result = regulator_enable(st->vdd_supply);
if (result) {
dev_err(dev, "Failed to enable vdd regulator: %d\n", result);
return result;
}
result = inv_mpu_core_enable_regulator_vddio(st);
if (result) {
regulator_disable(st->vdd_supply);
return result;
}
result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action,
st);
@ -1361,7 +1386,7 @@ static int inv_mpu_resume(struct device *dev)
int result;
mutex_lock(&st->lock);
result = inv_mpu_core_enable_regulator(st);
result = inv_mpu_core_enable_regulator_vddio(st);
if (result)
goto out_unlock;
@ -1379,7 +1404,7 @@ static int inv_mpu_suspend(struct device *dev)
mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, false);
inv_mpu_core_disable_regulator(st);
inv_mpu_core_disable_regulator_vddio(st);
mutex_unlock(&st->lock);
return result;

Просмотреть файл

@ -132,7 +132,8 @@ struct inv_mpu6050_hw {
* @chip_period: chip internal period estimation (~1kHz).
* @it_timestamp: timestamp from previous interrupt.
* @data_timestamp: timestamp for next data sample.
* @vddio_supply voltage regulator for the chip.
* @vdd_supply: VDD voltage regulator for the chip.
* @vddio_supply I/O voltage regulator for the chip.
* @magn_disabled: magnetometer disabled for backward compatibility reason.
* @magn_raw_to_gauss: coefficient to convert mag raw value to Gauss.
* @magn_orient: magnetometer sensor chip orientation if available.
@ -156,6 +157,7 @@ struct inv_mpu6050_state {
s64 chip_period;
s64 it_timestamp;
s64 data_timestamp;
struct regulator *vdd_supply;
struct regulator *vddio_supply;
bool magn_disabled;
s32 magn_raw_to_gauss[3];

Просмотреть файл

@ -106,14 +106,16 @@ struct st_lsm6dsx_sensor;
struct st_lsm6dsx_hw;
struct st_lsm6dsx_odr {
u16 hz;
u32 milli_hz;
u8 val;
};
#define ST_LSM6DSX_ODR_LIST_SIZE 6
struct st_lsm6dsx_odr_table_entry {
struct st_lsm6dsx_reg reg;
struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
int odr_len;
};
struct st_lsm6dsx_fs {
@ -328,7 +330,7 @@ struct st_lsm6dsx_sensor {
struct st_lsm6dsx_hw *hw;
u32 gain;
u16 odr;
u32 odr;
u16 watermark;
u8 sip;
@ -413,7 +415,7 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode);
int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val);
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val);
int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);
int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);

Просмотреть файл

@ -91,7 +91,7 @@ static int st_lsm6dsx_get_decimator_val(u8 val)
}
static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
u16 *max_odr, u16 *min_odr)
u32 *max_odr, u32 *min_odr)
{
struct st_lsm6dsx_sensor *sensor;
int i;
@ -106,16 +106,17 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
if (!(hw->enable_mask & BIT(sensor->id)))
continue;
*max_odr = max_t(u16, *max_odr, sensor->odr);
*min_odr = min_t(u16, *min_odr, sensor->odr);
*max_odr = max_t(u32, *max_odr, sensor->odr);
*min_odr = min_t(u32, *min_odr, sensor->odr);
}
}
static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
{
u16 max_odr, min_odr, sip = 0, ts_sip = 0;
const struct st_lsm6dsx_reg *ts_dec_reg;
struct st_lsm6dsx_sensor *sensor;
u16 sip = 0, ts_sip = 0;
u32 max_odr, min_odr;
int err = 0, i;
u8 data;

Просмотреть файл

@ -127,24 +127,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x20,
.mask = GENMASK(7, 5),
},
.odr_avl[0] = { 10, 0x01 },
.odr_avl[1] = { 50, 0x02 },
.odr_avl[2] = { 119, 0x03 },
.odr_avl[3] = { 238, 0x04 },
.odr_avl[4] = { 476, 0x05 },
.odr_avl[5] = { 952, 0x06 },
.odr_avl[0] = { 10000, 0x01 },
.odr_avl[1] = { 50000, 0x02 },
.odr_avl[2] = { 119000, 0x03 },
.odr_avl[3] = { 238000, 0x04 },
.odr_avl[4] = { 476000, 0x05 },
.odr_avl[5] = { 952000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 5),
},
.odr_avl[0] = { 15, 0x01 },
.odr_avl[1] = { 60, 0x02 },
.odr_avl[2] = { 119, 0x03 },
.odr_avl[3] = { 238, 0x04 },
.odr_avl[4] = { 476, 0x05 },
.odr_avl[5] = { 952, 0x06 },
.odr_avl[0] = { 14900, 0x01 },
.odr_avl[1] = { 59500, 0x02 },
.odr_avl[2] = { 119000, 0x03 },
.odr_avl[3] = { 238000, 0x04 },
.odr_avl[4] = { 476000, 0x05 },
.odr_avl[5] = { 952000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -227,24 +229,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -391,24 +395,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -564,24 +570,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -739,24 +747,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -934,24 +944,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -1109,24 +1121,26 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
.odr_avl[0] = { 12500, 0x01 },
.odr_avl[1] = { 26000, 0x02 },
.odr_avl[2] = { 52000, 0x03 },
.odr_avl[3] = { 104000, 0x04 },
.odr_avl[4] = { 208000, 0x05 },
.odr_avl[5] = { 416000, 0x06 },
.odr_len = 6,
},
},
.fs_table = {
@ -1344,36 +1358,37 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
return 0;
}
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val)
{
const struct st_lsm6dsx_odr_table_entry *odr_table;
int i;
odr_table = &sensor->hw->settings->odr_table[sensor->id];
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
for (i = 0; i < odr_table->odr_len; i++) {
/*
* ext devices can run at different odr respect to
* accel sensor
*/
if (odr_table->odr_avl[i].hz >= odr)
if (odr_table->odr_avl[i].milli_hz >= odr)
break;
}
if (i == ST_LSM6DSX_ODR_LIST_SIZE)
if (i == odr_table->odr_len)
return -EINVAL;
*val = odr_table->odr_avl[i].val;
return 0;
return odr_table->odr_avl[i].milli_hz;
}
static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
static int
st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u32 odr,
enum st_lsm6dsx_sensor_id id)
{
struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
if (odr > 0) {
if (hw->enable_mask & BIT(id))
return max_t(u16, ref->odr, odr);
return max_t(u32, ref->odr, odr);
else
return odr;
} else {
@ -1381,7 +1396,8 @@ static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
}
}
static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
static int
st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u32 req_odr)
{
struct st_lsm6dsx_sensor *ref_sensor = sensor;
struct st_lsm6dsx_hw *hw = sensor->hw;
@ -1395,7 +1411,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
case ST_LSM6DSX_ID_EXT1:
case ST_LSM6DSX_ID_EXT2:
case ST_LSM6DSX_ID_ACC: {
u16 odr;
u32 odr;
int i;
/*
@ -1435,7 +1451,7 @@ int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
bool enable)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
u16 odr = enable ? sensor->odr : 0;
u32 odr = enable ? sensor->odr : 0;
int err;
err = st_lsm6dsx_set_odr(sensor, odr);
@ -1461,7 +1477,7 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
if (err < 0)
return err;
delay = 1000000 / sensor->odr;
delay = 1000000000 / sensor->odr;
usleep_range(delay, 2 * delay);
err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
@ -1493,8 +1509,9 @@ static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
iio_device_release_direct_mode(iio_dev);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = sensor->odr;
ret = IIO_VAL_INT;
*val = sensor->odr / 1000;
*val2 = (sensor->odr % 1000) * 1000;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
case IIO_CHAN_INFO_SCALE:
*val = 0;
@ -1527,8 +1544,11 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_SAMP_FREQ: {
u8 data;
err = st_lsm6dsx_check_odr(sensor, val, &data);
if (!err)
val = val * 1000 + val2 / 1000;
val = st_lsm6dsx_check_odr(sensor, val, &data);
if (val < 0)
err = val;
else
sensor->odr = val;
break;
}
@ -1709,13 +1729,14 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
char *buf)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
enum st_lsm6dsx_sensor_id id = sensor->id;
struct st_lsm6dsx_hw *hw = sensor->hw;
const struct st_lsm6dsx_odr_table_entry *odr_table;
int i, len = 0;
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
hw->settings->odr_table[id].odr_avl[i].hz);
odr_table = &sensor->hw->settings->odr_table[sensor->id];
for (i = 0; i < odr_table->odr_len; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ",
odr_table->odr_avl[i].milli_hz / 1000,
odr_table->odr_avl[i].milli_hz % 1000);
buf[len - 1] = '\n';
return len;
@ -2021,7 +2042,7 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
sensor = iio_priv(iio_dev);
sensor->id = id;
sensor->hw = hw;
sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz;
sensor->odr = hw->settings->odr_table[id].odr_avl[0].milli_hz;
sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain;
sensor->watermark = 1;

Просмотреть файл

@ -51,10 +51,11 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = {
.addr = 0x60,
.mask = GENMASK(3, 2),
},
.odr_avl[0] = { 10, 0x0 },
.odr_avl[1] = { 20, 0x1 },
.odr_avl[2] = { 50, 0x2 },
.odr_avl[3] = { 100, 0x3 },
.odr_avl[0] = { 10000, 0x0 },
.odr_avl[1] = { 20000, 0x1 },
.odr_avl[2] = { 50000, 0x2 },
.odr_avl[3] = { 100000, 0x3 },
.odr_len = 4,
},
.fs_table = {
.fs_avl[0] = {
@ -93,11 +94,11 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = {
static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
{
struct st_lsm6dsx_sensor *sensor;
u16 odr;
u32 odr;
sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 13;
msleep((2000U / odr) + 1);
odr = (hw->enable_mask & BIT(ST_LSM6DSX_ID_ACC)) ? sensor->odr : 12500;
msleep((2000000U / odr) + 1);
}
/**
@ -317,17 +318,18 @@ st_lsm6dsx_shub_write_with_mask(struct st_lsm6dsx_sensor *sensor,
static int
st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor,
u16 odr, u16 *val)
u32 odr, u16 *val)
{
const struct st_lsm6dsx_ext_dev_settings *settings;
int i;
settings = sensor->ext_info.settings;
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
if (settings->odr_table.odr_avl[i].hz == odr)
for (i = 0; i < settings->odr_table.odr_len; i++) {
if (settings->odr_table.odr_avl[i].milli_hz == odr)
break;
}
if (i == ST_LSM6DSX_ODR_LIST_SIZE)
if (i == settings->odr_table.odr_len)
return -EINVAL;
*val = settings->odr_table.odr_avl[i].val;
@ -335,7 +337,7 @@ st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor,
}
static int
st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u32 odr)
{
const struct st_lsm6dsx_ext_dev_settings *settings;
u16 val;
@ -440,7 +442,7 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
if (err < 0)
return err;
delay = 1000000 / sensor->odr;
delay = 1000000000 / sensor->odr;
usleep_range(delay, 2 * delay);
len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3);
@ -480,8 +482,9 @@ st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev,
iio_device_release_direct_mode(iio_dev);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = sensor->odr;
ret = IIO_VAL_INT;
*val = sensor->odr / 1000;
*val2 = (sensor->odr % 1000) * 1000;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
case IIO_CHAN_INFO_SCALE:
*val = 0;
@ -512,6 +515,7 @@ st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_SAMP_FREQ: {
u16 data;
val = val * 1000 + val2 / 1000;
err = st_lsm6dsx_shub_get_odr_val(sensor, val, &data);
if (!err)
sensor->odr = val;
@ -537,12 +541,11 @@ st_lsm6dsx_shub_sampling_freq_avail(struct device *dev,
int i, len = 0;
settings = sensor->ext_info.settings;
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) {
u16 val = settings->odr_table.odr_avl[i].hz;
for (i = 0; i < settings->odr_table.odr_len; i++) {
u32 val = settings->odr_table.odr_avl[i].milli_hz;
if (val > 0)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
val);
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%03d ",
val / 1000, val % 1000);
}
buf[len - 1] = '\n';
@ -607,7 +610,7 @@ st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw,
sensor = iio_priv(iio_dev);
sensor->id = id;
sensor->hw = hw;
sensor->odr = info->odr_table.odr_avl[0].hz;
sensor->odr = info->odr_table.odr_avl[0].milli_hz;
sensor->gain = info->fs_table.fs_avl[0].gain;
sensor->ext_info.settings = info;
sensor->ext_info.addr = i2c_addr;

Просмотреть файл

@ -507,6 +507,17 @@ config VCNL4035
To compile this driver as a module, choose M here: the
module will be called vcnl4035.
config VEML6030
tristate "VEML6030 ambient light sensor"
select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VEML6030
ambient light sensor (ALS).
To compile this driver as a module, choose M here: the
module will be called veml6030.
config VEML6070
tristate "VEML6070 UV A light sensor"
depends on I2C

Просмотреть файл

@ -49,6 +49,7 @@ obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VCNL4035) += vcnl4035.o
obj-$(CONFIG_VEML6030) += veml6030.o
obj-$(CONFIG_VEML6070) += veml6070.o
obj-$(CONFIG_VL6180) += vl6180.o
obj-$(CONFIG_ZOPT2201) += zopt2201.o

Просмотреть файл

@ -0,0 +1,908 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* VEML6030 Ambient Light Sensor
*
* Copyright (c) 2019, Rishi Gupta <gupt21@gmail.com>
*
* Datasheet: https://www.vishay.com/docs/84366/veml6030.pdf
* Appnote-84367: https://www.vishay.com/docs/84367/designingveml6030.pdf
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
/* Device registers */
#define VEML6030_REG_ALS_CONF 0x00
#define VEML6030_REG_ALS_WH 0x01
#define VEML6030_REG_ALS_WL 0x02
#define VEML6030_REG_ALS_PSM 0x03
#define VEML6030_REG_ALS_DATA 0x04
#define VEML6030_REG_WH_DATA 0x05
#define VEML6030_REG_ALS_INT 0x06
/* Bit masks for specific functionality */
#define VEML6030_ALS_IT GENMASK(9, 6)
#define VEML6030_PSM GENMASK(2, 1)
#define VEML6030_ALS_PERS GENMASK(5, 4)
#define VEML6030_ALS_GAIN GENMASK(12, 11)
#define VEML6030_PSM_EN BIT(0)
#define VEML6030_INT_TH_LOW BIT(15)
#define VEML6030_INT_TH_HIGH BIT(14)
#define VEML6030_ALS_INT_EN BIT(1)
#define VEML6030_ALS_SD BIT(0)
/*
* The resolution depends on both gain and integration time. The
* cur_resolution stores one of the resolution mentioned in the
* table during startup and gets updated whenever integration time
* or gain is changed.
*
* Table 'resolution and maximum detection range' in appnote 84367
* is visualized as a 2D array. The cur_gain stores index of gain
* in this table (0-3) while the cur_integration_time holds index
* of integration time (0-5).
*/
struct veml6030_data {
struct i2c_client *client;
struct regmap *regmap;
int cur_resolution;
int cur_gain;
int cur_integration_time;
};
/* Integration time available in seconds */
static IIO_CONST_ATTR(in_illuminance_integration_time_available,
"0.025 0.05 0.1 0.2 0.4 0.8");
/*
* Scale is 1/gain. Value 0.125 is ALS gain x (1/8), 0.25 is
* ALS gain x (1/4), 1.0 = ALS gain x 1 and 2.0 is ALS gain x 2.
*/
static IIO_CONST_ATTR(in_illuminance_scale_available,
"0.125 0.25 1.0 2.0");
static struct attribute *veml6030_attributes[] = {
&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group veml6030_attr_group = {
.attrs = veml6030_attributes,
};
/*
* Persistence = 1/2/4/8 x integration time
* Minimum time for which light readings must stay above configured
* threshold to assert the interrupt.
*/
static const char * const period_values[] = {
"0.1 0.2 0.4 0.8",
"0.2 0.4 0.8 1.6",
"0.4 0.8 1.6 3.2",
"0.8 1.6 3.2 6.4",
"0.05 0.1 0.2 0.4",
"0.025 0.050 0.1 0.2"
};
/*
* Return list of valid period values in seconds corresponding to
* the currently active integration time.
*/
static ssize_t in_illuminance_period_available_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret, reg, x;
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct veml6030_data *data = iio_priv(indio_dev);
ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als conf register %d\n", ret);
return ret;
}
ret = ((reg >> 6) & 0xF);
switch (ret) {
case 0:
case 1:
case 2:
case 3:
x = ret;
break;
case 8:
x = 4;
break;
case 12:
x = 5;
break;
default:
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "%s\n", period_values[x]);
}
static IIO_DEVICE_ATTR_RO(in_illuminance_period_available, 0);
static struct attribute *veml6030_event_attributes[] = {
&iio_dev_attr_in_illuminance_period_available.dev_attr.attr,
NULL
};
static const struct attribute_group veml6030_event_attr_group = {
.attrs = veml6030_event_attributes,
};
static int veml6030_als_pwr_on(struct veml6030_data *data)
{
return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_SD, 0);
}
static int veml6030_als_shut_down(struct veml6030_data *data)
{
return regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_SD, 1);
}
static void veml6030_als_shut_down_action(void *data)
{
veml6030_als_shut_down(data);
}
static const struct iio_event_spec veml6030_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_PERIOD) |
BIT(IIO_EV_INFO_ENABLE),
},
};
/* Channel number */
enum veml6030_chan {
CH_ALS,
CH_WHITE,
};
static const struct iio_chan_spec veml6030_channels[] = {
{
.type = IIO_LIGHT,
.channel = CH_ALS,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_SCALE),
.event_spec = veml6030_event_spec,
.num_event_specs = ARRAY_SIZE(veml6030_event_spec),
},
{
.type = IIO_INTENSITY,
.channel = CH_WHITE,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PROCESSED),
},
};
static const struct regmap_config veml6030_regmap_config = {
.name = "veml6030_regmap",
.reg_bits = 8,
.val_bits = 16,
.max_register = VEML6030_REG_ALS_INT,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static int veml6030_get_intgrn_tm(struct iio_dev *indio_dev,
int *val, int *val2)
{
int ret, reg;
struct veml6030_data *data = iio_priv(indio_dev);
ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als conf register %d\n", ret);
return ret;
}
switch ((reg >> 6) & 0xF) {
case 0:
*val2 = 100000;
break;
case 1:
*val2 = 200000;
break;
case 2:
*val2 = 400000;
break;
case 3:
*val2 = 800000;
break;
case 8:
*val2 = 50000;
break;
case 12:
*val2 = 25000;
break;
default:
return -EINVAL;
}
*val = 0;
return IIO_VAL_INT_PLUS_MICRO;
}
static int veml6030_set_intgrn_tm(struct iio_dev *indio_dev,
int val, int val2)
{
int ret, new_int_time, int_idx;
struct veml6030_data *data = iio_priv(indio_dev);
if (val)
return -EINVAL;
switch (val2) {
case 25000:
new_int_time = 0x300;
int_idx = 5;
break;
case 50000:
new_int_time = 0x200;
int_idx = 4;
break;
case 100000:
new_int_time = 0x00;
int_idx = 3;
break;
case 200000:
new_int_time = 0x40;
int_idx = 2;
break;
case 400000:
new_int_time = 0x80;
int_idx = 1;
break;
case 800000:
new_int_time = 0xC0;
int_idx = 0;
break;
default:
return -EINVAL;
}
ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_IT, new_int_time);
if (ret) {
dev_err(&data->client->dev,
"can't update als integration time %d\n", ret);
return ret;
}
/*
* Cache current integration time and update resolution. For every
* increase in integration time to next level, resolution is halved
* and vice-versa.
*/
if (data->cur_integration_time < int_idx)
data->cur_resolution <<= int_idx - data->cur_integration_time;
else if (data->cur_integration_time > int_idx)
data->cur_resolution >>= data->cur_integration_time - int_idx;
data->cur_integration_time = int_idx;
return ret;
}
static int veml6030_read_persistence(struct iio_dev *indio_dev,
int *val, int *val2)
{
int ret, reg, period, x, y;
struct veml6030_data *data = iio_priv(indio_dev);
ret = veml6030_get_intgrn_tm(indio_dev, &x, &y);
if (ret < 0)
return ret;
ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als conf register %d\n", ret);
}
/* integration time multiplied by 1/2/4/8 */
period = y * (1 << ((reg >> 4) & 0x03));
*val = period / 1000000;
*val2 = period % 1000000;
return IIO_VAL_INT_PLUS_MICRO;
}
static int veml6030_write_persistence(struct iio_dev *indio_dev,
int val, int val2)
{
int ret, period, x, y;
struct veml6030_data *data = iio_priv(indio_dev);
ret = veml6030_get_intgrn_tm(indio_dev, &x, &y);
if (ret < 0)
return ret;
if (!val) {
period = val2 / y;
} else {
if ((val == 1) && (val2 == 600000))
period = 1600000 / y;
else if ((val == 3) && (val2 == 200000))
period = 3200000 / y;
else if ((val == 6) && (val2 == 400000))
period = 6400000 / y;
else
period = -1;
}
if (period <= 0 || period > 8 || hweight8(period) != 1)
return -EINVAL;
ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_PERS, (ffs(period) - 1) << 4);
if (ret)
dev_err(&data->client->dev,
"can't set persistence value %d\n", ret);
return ret;
}
static int veml6030_set_als_gain(struct iio_dev *indio_dev,
int val, int val2)
{
int ret, new_gain, gain_idx;
struct veml6030_data *data = iio_priv(indio_dev);
if (val == 0 && val2 == 125000) {
new_gain = 0x1000; /* 0x02 << 11 */
gain_idx = 3;
} else if (val == 0 && val2 == 250000) {
new_gain = 0x1800;
gain_idx = 2;
} else if (val == 1 && val2 == 0) {
new_gain = 0x00;
gain_idx = 1;
} else if (val == 2 && val2 == 0) {
new_gain = 0x800;
gain_idx = 0;
} else {
return -EINVAL;
}
ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_GAIN, new_gain);
if (ret) {
dev_err(&data->client->dev,
"can't set als gain %d\n", ret);
return ret;
}
/*
* Cache currently set gain & update resolution. For every
* increase in the gain to next level, resolution is halved
* and vice-versa.
*/
if (data->cur_gain < gain_idx)
data->cur_resolution <<= gain_idx - data->cur_gain;
else if (data->cur_gain > gain_idx)
data->cur_resolution >>= data->cur_gain - gain_idx;
data->cur_gain = gain_idx;
return ret;
}
static int veml6030_get_als_gain(struct iio_dev *indio_dev,
int *val, int *val2)
{
int ret, reg;
struct veml6030_data *data = iio_priv(indio_dev);
ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als conf register %d\n", ret);
return ret;
}
switch ((reg >> 11) & 0x03) {
case 0:
*val = 1;
*val2 = 0;
break;
case 1:
*val = 2;
*val2 = 0;
break;
case 2:
*val = 0;
*val2 = 125000;
break;
case 3:
*val = 0;
*val2 = 250000;
break;
default:
return -EINVAL;
}
return IIO_VAL_INT_PLUS_MICRO;
}
static int veml6030_read_thresh(struct iio_dev *indio_dev,
int *val, int *val2, int dir)
{
int ret, reg;
struct veml6030_data *data = iio_priv(indio_dev);
if (dir == IIO_EV_DIR_RISING)
ret = regmap_read(data->regmap, VEML6030_REG_ALS_WH, &reg);
else
ret = regmap_read(data->regmap, VEML6030_REG_ALS_WL, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als threshold value %d\n", ret);
return ret;
}
*val = reg & 0xffff;
return IIO_VAL_INT;
}
static int veml6030_write_thresh(struct iio_dev *indio_dev,
int val, int val2, int dir)
{
int ret;
struct veml6030_data *data = iio_priv(indio_dev);
if (val > 0xFFFF || val < 0 || val2)
return -EINVAL;
if (dir == IIO_EV_DIR_RISING) {
ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, val);
if (ret)
dev_err(&data->client->dev,
"can't set high threshold %d\n", ret);
} else {
ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, val);
if (ret)
dev_err(&data->client->dev,
"can't set low threshold %d\n", ret);
}
return ret;
}
/*
* Provide both raw as well as light reading in lux.
* light (in lux) = resolution * raw reading
*/
static int veml6030_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
int ret, reg;
struct veml6030_data *data = iio_priv(indio_dev);
struct regmap *regmap = data->regmap;
struct device *dev = &data->client->dev;
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_LIGHT:
ret = regmap_read(regmap, VEML6030_REG_ALS_DATA, &reg);
if (ret < 0) {
dev_err(dev, "can't read als data %d\n", ret);
return ret;
}
if (mask == IIO_CHAN_INFO_PROCESSED) {
*val = (reg * data->cur_resolution) / 10000;
*val2 = (reg * data->cur_resolution) % 10000;
return IIO_VAL_INT_PLUS_MICRO;
}
*val = reg;
return IIO_VAL_INT;
case IIO_INTENSITY:
ret = regmap_read(regmap, VEML6030_REG_WH_DATA, &reg);
if (ret < 0) {
dev_err(dev, "can't read white data %d\n", ret);
return ret;
}
if (mask == IIO_CHAN_INFO_PROCESSED) {
*val = (reg * data->cur_resolution) / 10000;
*val2 = (reg * data->cur_resolution) % 10000;
return IIO_VAL_INT_PLUS_MICRO;
}
*val = reg;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_INT_TIME:
if (chan->type == IIO_LIGHT)
return veml6030_get_intgrn_tm(indio_dev, val, val2);
return -EINVAL;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_LIGHT)
return veml6030_get_als_gain(indio_dev, val, val2);
return -EINVAL;
default:
return -EINVAL;
}
}
static int veml6030_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
switch (chan->type) {
case IIO_LIGHT:
return veml6030_set_intgrn_tm(indio_dev, val, val2);
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_LIGHT:
return veml6030_set_als_gain(indio_dev, val, val2);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int veml6030_read_event_val(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int *val, int *val2)
{
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
case IIO_EV_DIR_RISING:
case IIO_EV_DIR_FALLING:
return veml6030_read_thresh(indio_dev, val, val2, dir);
default:
return -EINVAL;
}
break;
case IIO_EV_INFO_PERIOD:
return veml6030_read_persistence(indio_dev, val, val2);
default:
return -EINVAL;
}
}
static int veml6030_write_event_val(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
int val, int val2)
{
switch (info) {
case IIO_EV_INFO_VALUE:
return veml6030_write_thresh(indio_dev, val, val2, dir);
case IIO_EV_INFO_PERIOD:
return veml6030_write_persistence(indio_dev, val, val2);
default:
return -EINVAL;
}
}
static int veml6030_read_interrupt_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir)
{
int ret, reg;
struct veml6030_data *data = iio_priv(indio_dev);
ret = regmap_read(data->regmap, VEML6030_REG_ALS_CONF, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als conf register %d\n", ret);
return ret;
}
if (reg & VEML6030_ALS_INT_EN)
return 1;
else
return 0;
}
/*
* Sensor should not be measuring light when interrupt is configured.
* Therefore correct sequence to configure interrupt functionality is:
* shut down -> enable/disable interrupt -> power on
*
* state = 1 enables interrupt, state = 0 disables interrupt
*/
static int veml6030_write_interrupt_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, int state)
{
int ret;
struct veml6030_data *data = iio_priv(indio_dev);
if (state < 0 || state > 1)
return -EINVAL;
ret = veml6030_als_shut_down(data);
if (ret < 0) {
dev_err(&data->client->dev,
"can't disable als to configure interrupt %d\n", ret);
return ret;
}
/* enable interrupt + power on */
ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_CONF,
VEML6030_ALS_INT_EN | VEML6030_ALS_SD, state << 1);
if (ret)
dev_err(&data->client->dev,
"can't enable interrupt & poweron als %d\n", ret);
return ret;
}
static const struct iio_info veml6030_info = {
.read_raw = veml6030_read_raw,
.write_raw = veml6030_write_raw,
.read_event_value = veml6030_read_event_val,
.write_event_value = veml6030_write_event_val,
.read_event_config = veml6030_read_interrupt_config,
.write_event_config = veml6030_write_interrupt_config,
.attrs = &veml6030_attr_group,
.event_attrs = &veml6030_event_attr_group,
};
static const struct iio_info veml6030_info_no_irq = {
.read_raw = veml6030_read_raw,
.write_raw = veml6030_write_raw,
.attrs = &veml6030_attr_group,
};
static irqreturn_t veml6030_event_handler(int irq, void *private)
{
int ret, reg, evtdir;
struct iio_dev *indio_dev = private;
struct veml6030_data *data = iio_priv(indio_dev);
ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &reg);
if (ret) {
dev_err(&data->client->dev,
"can't read als interrupt register %d\n", ret);
return IRQ_HANDLED;
}
/* Spurious interrupt handling */
if (!(reg & (VEML6030_INT_TH_HIGH | VEML6030_INT_TH_LOW)))
return IRQ_NONE;
if (reg & VEML6030_INT_TH_HIGH)
evtdir = IIO_EV_DIR_RISING;
else
evtdir = IIO_EV_DIR_FALLING;
iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_INTENSITY,
0, IIO_EV_TYPE_THRESH, evtdir),
iio_get_time_ns(indio_dev));
return IRQ_HANDLED;
}
/*
* Set ALS gain to 1/8, integration time to 100 ms, PSM to mode 2,
* persistence to 1 x integration time and the threshold
* interrupt disabled by default. First shutdown the sensor,
* update registers and then power on the sensor.
*/
static int veml6030_hw_init(struct iio_dev *indio_dev)
{
int ret, val;
struct veml6030_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
ret = veml6030_als_shut_down(data);
if (ret) {
dev_err(&client->dev, "can't shutdown als %d\n", ret);
return ret;
}
ret = regmap_write(data->regmap, VEML6030_REG_ALS_CONF, 0x1001);
if (ret) {
dev_err(&client->dev, "can't setup als configs %d\n", ret);
return ret;
}
ret = regmap_update_bits(data->regmap, VEML6030_REG_ALS_PSM,
VEML6030_PSM | VEML6030_PSM_EN, 0x03);
if (ret) {
dev_err(&client->dev, "can't setup default PSM %d\n", ret);
return ret;
}
ret = regmap_write(data->regmap, VEML6030_REG_ALS_WH, 0xFFFF);
if (ret) {
dev_err(&client->dev, "can't setup high threshold %d\n", ret);
return ret;
}
ret = regmap_write(data->regmap, VEML6030_REG_ALS_WL, 0x0000);
if (ret) {
dev_err(&client->dev, "can't setup low threshold %d\n", ret);
return ret;
}
ret = veml6030_als_pwr_on(data);
if (ret) {
dev_err(&client->dev, "can't poweron als %d\n", ret);
return ret;
}
/* Wait 4 ms to let processor & oscillator start correctly */
usleep_range(4000, 4002);
/* Clear stale interrupt status bits if any during start */
ret = regmap_read(data->regmap, VEML6030_REG_ALS_INT, &val);
if (ret < 0) {
dev_err(&client->dev,
"can't clear als interrupt status %d\n", ret);
return ret;
}
/* Cache currently active measurement parameters */
data->cur_gain = 3;
data->cur_resolution = 4608;
data->cur_integration_time = 3;
return ret;
}
static int veml6030_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct veml6030_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "i2c adapter doesn't support plain i2c\n");
return -EOPNOTSUPP;
}
regmap = devm_regmap_init_i2c(client, &veml6030_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "can't setup regmap\n");
return PTR_ERR(regmap);
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->regmap = regmap;
indio_dev->dev.parent = &client->dev;
indio_dev->name = "veml6030";
indio_dev->channels = veml6030_channels;
indio_dev->num_channels = ARRAY_SIZE(veml6030_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, veml6030_event_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"veml6030", indio_dev);
if (ret < 0) {
dev_err(&client->dev,
"irq %d request failed\n", client->irq);
return ret;
}
indio_dev->info = &veml6030_info;
} else {
indio_dev->info = &veml6030_info_no_irq;
}
ret = veml6030_hw_init(indio_dev);
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(&client->dev,
veml6030_als_shut_down_action, data);
if (ret < 0)
return ret;
return devm_iio_device_register(&client->dev, indio_dev);
}
static int __maybe_unused veml6030_runtime_suspend(struct device *dev)
{
int ret;
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct veml6030_data *data = iio_priv(indio_dev);
ret = veml6030_als_shut_down(data);
if (ret < 0)
dev_err(&data->client->dev, "can't suspend als %d\n", ret);
return ret;
}
static int __maybe_unused veml6030_runtime_resume(struct device *dev)
{
int ret;
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct veml6030_data *data = iio_priv(indio_dev);
ret = veml6030_als_pwr_on(data);
if (ret < 0)
dev_err(&data->client->dev, "can't resume als %d\n", ret);
return ret;
}
static const struct dev_pm_ops veml6030_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(veml6030_runtime_suspend,
veml6030_runtime_resume, NULL)
};
static const struct of_device_id veml6030_of_match[] = {
{ .compatible = "vishay,veml6030" },
{ }
};
MODULE_DEVICE_TABLE(of, veml6030_of_match);
static const struct i2c_device_id veml6030_id[] = {
{ "veml6030", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, veml6030_id);
static struct i2c_driver veml6030_driver = {
.driver = {
.name = "veml6030",
.of_match_table = veml6030_of_match,
.pm = &veml6030_pm_ops,
},
.probe = veml6030_probe,
.id_table = veml6030_id,
};
module_i2c_driver(veml6030_driver);
MODULE_AUTHOR("Rishi Gupta <gupt21@gmail.com>");
MODULE_DESCRIPTION("VEML6030 Ambient Light Sensor");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -114,6 +114,7 @@ static int cros_ec_baro_write(struct iio_dev *indio_dev,
static const struct iio_info cros_ec_baro_info = {
.read_raw = &cros_ec_baro_read,
.write_raw = &cros_ec_baro_write,
.read_avail = &cros_ec_sensors_core_read_avail,
};
static int cros_ec_baro_probe(struct platform_device *pdev)
@ -149,6 +150,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_FREQUENCY);
channel->info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_SAMP_FREQ);
channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
channel->scan_type.shift = 0;

Просмотреть файл

@ -129,6 +129,7 @@ static inline int adis_read_reg_16(struct adis *adis, unsigned int reg,
int ret;
ret = adis_read_reg(adis, reg, &tmp, 2);
if (ret == 0)
*val = tmp;
return ret;
@ -147,6 +148,7 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
int ret;
ret = adis_read_reg(adis, reg, &tmp, 4);
if (ret == 0)
*val = tmp;
return ret;

Просмотреть файл

@ -1,3 +1,4 @@
iio_utils-y += iio_utils.o
lsiio-y += lsiio.o iio_utils.o
iio_event_monitor-y += iio_event_monitor.o iio_utils.o
iio_generic_buffer-y += iio_generic_buffer.o iio_utils.o

Просмотреть файл

@ -32,20 +32,24 @@ $(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio
prepare: $(OUTPUT)include/linux/iio
IIO_UTILS_IN := $(OUTPUT)iio_utils-in.o
$(IIO_UTILS_IN): prepare FORCE
$(Q)$(MAKE) $(build)=iio_utils
LSIIO_IN := $(OUTPUT)lsiio-in.o
$(LSIIO_IN): prepare FORCE
$(LSIIO_IN): prepare FORCE $(OUTPUT)iio_utils-in.o
$(Q)$(MAKE) $(build)=lsiio
$(OUTPUT)lsiio: $(LSIIO_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
IIO_EVENT_MONITOR_IN := $(OUTPUT)iio_event_monitor-in.o
$(IIO_EVENT_MONITOR_IN): prepare FORCE
$(IIO_EVENT_MONITOR_IN): prepare FORCE $(OUTPUT)iio_utils-in.o
$(Q)$(MAKE) $(build)=iio_event_monitor
$(OUTPUT)iio_event_monitor: $(IIO_EVENT_MONITOR_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
IIO_GENERIC_BUFFER_IN := $(OUTPUT)iio_generic_buffer-in.o
$(IIO_GENERIC_BUFFER_IN): prepare FORCE
$(IIO_GENERIC_BUFFER_IN): prepare FORCE $(OUTPUT)iio_utils-in.o
$(Q)$(MAKE) $(build)=iio_generic_buffer
$(OUTPUT)iio_generic_buffer: $(IIO_GENERIC_BUFFER_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@