Commit e2664d08 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-5.10a-take2' of...

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

Jonathan writes:

First set of new device support, features and cleanup for IIO in 5.10 cycle, take 2

A few changes to how I write this cover letter.
* Started to use manufacturer prefixes to group changes better.
* Stop list minor formatting etc changes.
* Whilst I appreciate those changes, we don't need to call them out here.

New device support:
* adi,adxrs290
  - New driver for this gyroscope with dt bindings. One fix follows.
* ams,as73211
  - New driver for this colour sensor with dt bindings. Also includes
    docs for XYZ modifiers as used for the CIE colour space. Sysfs docs.
* atlas,atlas-ezo-sensor
  - Support O_2 sensor, includes new modifier for concentration.
  - Support humidity sensor.
* ti,hdc2010
  - New driver support hdc2010 and hdc2080 humidity sensors. Includes dt
    bindings.

Cleanup, minor fixes and features
* core
  - Make the trigger related stub functions static inline, avoiding some build
   warnings.
  - buffer-dmaengine. Allow adjusting bytes_used with residue info.
* dev_error_probe to replace open coded equivalent in many drivers.
* docs and comment fixes
  - Fix some typos, doubled words, capitalisation and punctuation.
* dt binding conversions to yaml
  - lltc,ltc2497
  - lltc,ltc2632
  - maxim,max11100
  - maxim,max1118
  - maxim,max9611
  - microchip,mcp3201
  - microchip,mcp342x (add to trivial devices)
  - ti,adc0832
  - ti,adc108s102
  - ti,adc128s052
  - ti,adc161s626
  - ti,ads8344
  - ti,tlc4541 (includes adding an accidentally dropped original binding doc)
* adi,adi-axi-adc
  - Use kobj_to_dev instead of open coding.
* adi,ad5686
  - Constify iio_chan_spec
* adi,ad8366
  - Add HMC1119 to kconfig help text as the driver supports it.
* adi,ad9523
  - Use devm for reset of probe and drop remove.
* adi,adxl372
  - Tidy up alignment
  - Add OF table
  - Add peak mode support with some docs.
* bosch,bma220 (general tidy up)
  - Fix some return codes.
  - Use read_avail callback rather than open coding attrs.
  - Use dev_get_drvdata rather than dance via to_spi_device()
  - Mark PM functions as __maybe_unused rather than #ifdef fun.
  - Drop ACPI_PTR protections and ifdefs.
  - Tidy up header ordering.
  - BIT and GENMASK
* broadcom,bcm_iproc
  - Drop of_match_ptr protection and switch to mod_devicetable.h
    Part of general move to get this anti-pattern out of IIO.
* melexis,mlx90614
  - Simplify some calculations.
  - Add some kernel_doc
  - Use regmap poll loop rather than open coding.
  - Add extended calibration option.
* sensortec,sx9310, wide ranging set of fixes and cleanups.
  - Document dt-binding.
  - Rename some macros to align better with spec sheet
  - Fix some issues with irq handling.
  - Drop of_match_ptr and ACPI_PTR macros to avoid unused warnings etc.
  - Switch to probe_new
  - Fix memory alignment for iio_push_to_buffers_with_timestamp()
  - Use long for bitmaps to allow use of for_each_bit_set()
  - Use regmap_read_poll instead of opencoding.
  - Simplify error paths
  - Enabled regulators at probe.
  - Use trigger flags from firmware rather than forcing them in the driver.
* ti,adc081c
  - Drop ACPI IDs that are not likely to be official ones and we don't believe
    anyone is using.
* ti,adc108s102
  - Drop CONFIG_OF and of_match_ptr protections.
* ti,adc128s052
  - Drop of_match_ptr protection and include mod_devicetable.h
* ti,dac5571
  - Support powerdown for mutlichannel usecases.
* xpowers,axp20x
  - Convert from OF to generic fw / device properties. Unlikely anyone will
    use this with anything other than devicetree, but this is part of a
    general move across IIO.

* tag 'iio-for-5.10a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (96 commits)
  drivers/iio/humidity/hdc2010.c:305:2-3: Unneeded semicolon
  iio: accel: bma220: Remove unneeded blank lines
  iio: accel: bma220: Use BIT() and GENMASK() macros
  iio: accel: bma220: Group IIO headers together
  iio: accel: bma220: Drop ACPI_PTR() and accompanying ifdeffery
  iio: accel: bma220: Mark PM functions as __maybe_unused
  iio: accel: bma220: Use dev_get_drvdata() directly
  iio: accel: bma220: Convert to use ->read_avail()
  iio: accel: bma220: Fix returned codes from bma220_init(), bma220_deinit()
  dt-bindings: iio: adc: microchip,mcp3201 yaml conversion.
  iio: buffer-dmaengine: adjust `bytes_used` with residue info
  dt-bindings: iio: adc: ti,tlc4541 binding conversion
  dt-bindings: iio: adc: tlc4541 - recover accidentally dropped binding doc
  dt-bindings: iio: adc: ti,ads8344 yaml conversion
  dt-bindings: iio: adc: ti,adc128s052 yaml conversion.
  dt-bindings: iio: adc: ti,adc0832 yaml conversion.
  dt-bindings: iio: adc: ti,adc161s626 yaml conversion.
  dt-bindings: iio: adc: lltc,ltc2497 yaml conversion.
  dt-bindings: iio: adc: ti,adc108s102 yaml conversion
  dt-bindings: trivial-devices: Add mcp342x ADCs and drop separate binding doc.
  ...
parents 76f50ad9 2f0472a1
......@@ -40,6 +40,7 @@ Description:
buffered samples and events for device X.
What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_sampling_frequency
What: /sys/bus/iio/devices/iio:deviceX/buffer/sampling_frequency
What: /sys/bus/iio/devices/triggerX/sampling_frequency
KernelVersion: 2.6.35
......@@ -49,12 +50,13 @@ Description:
resulting sampling frequency. In many devices this
parameter has an effect on input filters etc. rather than
simply controlling when the input is sampled. As this
effects data ready triggers, hardware buffers and the sysfs
affects data ready triggers, hardware buffers and the sysfs
direct access interfaces, it may be found in any of the
relevant directories. If it effects all of the above
relevant directories. If it affects all of the above
then it is to be found in the base device directory.
What: /sys/bus/iio/devices/iio:deviceX/sampling_frequency_available
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_sampling_frequency_available
What: /sys/bus/iio/devices/iio:deviceX/in_proximity_sampling_frequency_available
What: /sys/.../iio:deviceX/buffer/sampling_frequency_available
What: /sys/bus/iio/devices/triggerX/sampling_frequency_available
......@@ -374,6 +376,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale
What: /sys/bus/iio/devices/iio:deviceX/in_countY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_scale
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_scale
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
......@@ -401,21 +406,21 @@ Description:
Hardware applied calibration offset (assumed to fix production
inaccuracies).
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_calibscale
......@@ -483,7 +488,8 @@ Description:
If a discrete set of scale values is available, they
are listed in this attribute.
What /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_red_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_green_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_blue_hardwaregain
......@@ -494,6 +500,13 @@ Description:
Hardware applied gain factor. If shared across all channels,
<type>_hardwaregain is used.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain_available
KernelVersion: 5.10
Contact: linux-iio@vger.kernel.org
Description:
Lists all available hardware applied gain factors. Shared across all
channels.
What: /sys/.../in_accel_filter_low_pass_3db_frequency
What: /sys/.../in_magn_filter_low_pass_3db_frequency
What: /sys/.../in_anglvel_filter_low_pass_3db_frequency
......@@ -750,9 +763,9 @@ What: /sys/.../events/in_voltageY_raw_thresh_falling_value
What: /sys/.../events/in_tempY_raw_thresh_rising_value
What: /sys/.../events/in_tempY_raw_thresh_falling_value
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_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
......@@ -832,11 +845,11 @@ What: /sys/.../events/in_tempY_thresh_rising_hysteresis
What: /sys/.../events/in_tempY_thresh_falling_hysteresis
What: /sys/.../events/in_tempY_thresh_either_hysteresis
What: /sys/.../events/in_illuminance0_thresh_falling_hysteresis
what: /sys/.../events/in_illuminance0_thresh_rising_hysteresis
what: /sys/.../events/in_illuminance0_thresh_either_hysteresis
what: /sys/.../events/in_proximity0_thresh_falling_hysteresis
what: /sys/.../events/in_proximity0_thresh_rising_hysteresis
what: /sys/.../events/in_proximity0_thresh_either_hysteresis
What: /sys/.../events/in_illuminance0_thresh_rising_hysteresis
What: /sys/.../events/in_illuminance0_thresh_either_hysteresis
What: /sys/.../events/in_proximity0_thresh_falling_hysteresis
What: /sys/.../events/in_proximity0_thresh_rising_hysteresis
What: /sys/.../events/in_proximity0_thresh_either_hysteresis
KernelVersion: 3.13
Contact: linux-iio@vger.kernel.org
Description:
......@@ -1013,7 +1026,7 @@ What: /sys/.../events/in_activity_running_thresh_falling_en
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
Enables or disables activitity events. Depending on direction
Enables or disables activity events. Depending on direction
an event is generated when sensor ENTERS or LEAVES a given state.
What: /sys/.../events/in_activity_still_thresh_rising_value
......@@ -1333,6 +1346,7 @@ Description:
standardised CIE Erythemal Action Spectrum. UV index values range
from 0 (low) to >=11 (extreme).
What: /sys/.../iio:deviceX/in_intensity_integration_time
What: /sys/.../iio:deviceX/in_intensity_red_integration_time
What: /sys/.../iio:deviceX/in_intensity_green_integration_time
What: /sys/.../iio:deviceX/in_intensity_blue_integration_time
......@@ -1342,7 +1356,8 @@ KernelVersion: 3.12
Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to get/set the integration time in
seconds.
seconds. If shared across all channels of a given type,
<type>_integration_time is used.
What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_integration_time
KernelVersion: 4.0
......@@ -1564,6 +1579,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_ethanol_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_h2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_o2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_o2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
KernelVersion: 4.3
......@@ -1740,3 +1757,12 @@ KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
One of the following thermocouple types: B, E, J, K, N, R, S, T.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_x_raw
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_y_raw
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_z_raw
KernelVersion: 5.10
Contact: linux-iio@vger.kernel.org
Description:
Unscaled light intensity according to CIE 1931/DIN 5033 color space.
Units after application of scale are nano nanowatts per square meter.
What: /sys/bus/iio/devices/triggerX/name = "adxl372-devX-peak"
KernelVersion:
Contact: linux-iio@vger.kernel.org
Description:
The adxl372 accelerometer kernel module provides an additional trigger,
which sets the device in a mode in which it will record only the peak acceleration
sensed over the set period of time in the events sysfs.
What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw
What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available
KernelVersion: 5.3.8
Contact: linux-iio@vger.kernel.org
Description:
Controls the heater device within the humidity sensor to get
rid of excess condensation.
Valid control values are 0 = OFF, and 1 = ON.
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/lltc,ltc2497.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology / Analog Devices LTC2497 ADC
maintainers:
- Michael Hennerich <michael.hennerich@analog.com>
description: |
16bit ADC supporting up to 16 single ended or 8 differential inputs.
I2C interface.
properties:
compatible:
const:
lltc,ltc2497
reg: true
vref-supply: true
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@76 {
compatible = "lltc,ltc2497";
reg = <0x76>;
vref-supply = <&ltc2497_reg>;
#io-channel-cells = <1>;
};
};
...
* Linear Technology / Analog Devices LTC2497 ADC
Required properties:
- compatible: Must be "lltc,ltc2497"
- reg: Must contain the ADC I2C address
- vref-supply: The regulator supply for ADC reference voltage
Example:
ltc2497: adc@76 {
compatible = "lltc,ltc2497";
reg = <0x76>;
vref-supply = <&ltc2497_reg>;
};
* Maxim max11100 Analog to Digital Converter (ADC)
Required properties:
- compatible: Should be "maxim,max11100"
- reg: the adc unit address
- vref-supply: phandle to the regulator that provides reference voltage
Optional properties:
- spi-max-frequency: SPI maximum frequency
Example:
max11100: adc@0 {
compatible = "maxim,max11100";
reg = <0>;
vref-supply = <&adc0_vref>;
spi-max-frequency = <240000>;
};
* MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs
Required properties:
- compatible: Should be one of
* "maxim,max1117"
* "maxim,max1118"
* "maxim,max1119"
- reg: spi chip select number for the device
- (max1118 only) vref-supply: The regulator supply for ADC reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "maxim,max1118";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
};
* Maxim max9611/max9612 current sense amplifier with 12-bits ADC interface
Maxim max9611/max9612 is an high-side current sense amplifier with integrated
12-bits ADC communicating over I2c bus.
The device node for this driver shall be a child of a I2c controller.
Required properties
- compatible: Should be "maxim,max9611" or "maxim,max9612"
- reg: The 7-bits long I2c address of the device
- shunt-resistor-micro-ohms: Value, in micro Ohms, of the current sense shunt
resistor
Example:
&i2c4 {
csa: adc@7c {
compatible = "maxim,max9611";
reg = <0x7c>;
shunt-resistor-micro-ohms = <5000>;
};
};
This device node describes a current sense amplifier sitting on I2c4 bus
with address 0x7c (read address is 0xf9, write address is 0xf8).
A sense resistor of 0,005 Ohm is installed between RS+ and RS- current-sensing
inputs.
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/maxim,max11100.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX11100 ADC
maintainers:
- Jacopo Mondi <jacopo@jmondi.org>
description: |
Single channel 16 bit ADC with SPI interface.
properties:
compatible:
const: maxim,max11100
reg:
maxItems: 1
vref-supply:
description: External reference, needed to establish input scaling.
spi-max-frequency:
minimum: 100000
maximum: 4800000
additionalProperties: false
required:
- compatible
- reg
- vref-supply
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "maxim,max11100";
reg = <0>;
vref-supply = <&adc_vref>;
spi-max-frequency = <240000>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/maxim,max1118.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX1118 and similar ADCs
maintainers:
- Akinobu Mita <akinobu.mita@gmail.com>
description: |
Dual channel 8bit ADCs.
properties:
compatible:
enum:
- maxim,max1117
- maxim,max1118
- maxim,max1119
reg:
maxItems: 1
spi-max-frequency:
maximum: 5000000
vref-supply:
description: External reference, needed to establish input scaling
if:
properties:
compatible:
contains:
const: maxim,max1118
then:
required:
- vref-supply
else:
properties:
vref-supply: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "maxim,max1118";
reg = <0>;
vref-supply = <&adc_vref>;
spi-max-frequency = <1000000>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/maxim,max9611.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX9611 and similar current sense amplifiers with integrated ADCs
maintainers:
- Jacopo Mondi <jacopo@jmondi.org>
description: |
These devices combine a high-side current sense amplifier with a 12 bit ADC.
They have an i2c interface.
properties:
compatible:
enum:
- maxim,max9611
- maxim,max9612
reg:
maxItems: 1
shunt-resistor-micro-ohms:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Value in micro Ohms of the shunt resistor connected between the RS+ and
RS- inputs, across which the current is measured. Value needed to compute
the scaling of the measured current.
additionalProperties: false
required:
- compatible
- reg
- shunt-resistor-micro-ohms
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@7c {
compatible = "maxim,max9611";
reg = <0x7c>;
shunt-resistor-micro-ohms = <5000>;
};
};
...
* Microchip Analog to Digital Converter (ADC)
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in
Documentation/devicetree/bindings/spi/spi-bus.txt
must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"mcp3001" (DEPRECATED)
"mcp3002" (DEPRECATED)
"mcp3004" (DEPRECATED)
"mcp3008" (DEPRECATED)
"mcp3201" (DEPRECATED)
"mcp3202" (DEPRECATED)
"mcp3204" (DEPRECATED)
"mcp3208" (DEPRECATED)
"mcp3301" (DEPRECATED)
"microchip,mcp3001"
"microchip,mcp3002"
"microchip,mcp3004"
"microchip,mcp3008"
"microchip,mcp3201"
"microchip,mcp3202"
"microchip,mcp3204"
"microchip,mcp3208"
"microchip,mcp3301"
"microchip,mcp3550-50"
"microchip,mcp3550-60"
"microchip,mcp3551"
"microchip,mcp3553"
NOTE: The use of the compatibles with no vendor prefix
is deprecated and only listed because old DT use them.
- spi-cpha, spi-cpol (boolean):
Either SPI mode (0,0) or (1,1) must be used, so specify
none or both of spi-cpha, spi-cpol. The MCP3550/1/3
is more efficient in mode (1,1) as only 3 instead of
4 bytes need to be read from the ADC, but not all SPI
masters support it.
- vref-supply: Phandle to the external reference voltage supply.
Examples:
spi_controller {
mcp3x0x@0 {
compatible = "microchip,mcp3002";
reg = <0>;
spi-max-frequency = <1000000>;
vref-supply = <&vref_reg>;
};
};
* Microchip mcp3421/2/3/4/6/7/8 chip family (ADC)
Required properties:
- compatible: Should be
"microchip,mcp3421" or
"microchip,mcp3422" or
"microchip,mcp3423" or
"microchip,mcp3424" or
"microchip,mcp3425" or
"microchip,mcp3426" or
"microchip,mcp3427" or
"microchip,mcp3428"
- reg: I2C address for the device
Example:
adc@0 {
compatible = "microchip,mcp3424";
reg = <0x68>;
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/microchip,mcp3201.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip mcp3201 and similar ADCs
maintainers:
- Oskar Andero <oskar.andero@gmail.com>
description: |
Family of simple ADCs with an I2C inteface.
properties:
compatible:
enum:
- microchip,mcp3001
- microchip,mcp3002
- microchip,mcp3004
- microchip,mcp3008
- microchip,mcp3201
- microchip,mcp3202
- microchip,mcp3204
- microchip,mcp3208
- microchip,mcp3301
- microchip,mcp3550-50
- microchip,mcp3550-60
- microchip,mcp3551
- microchip,mcp3553
reg:
maxItems: 1
spi-max-frequency: true
spi-cpha: true
spi-cpol: true
vref-supply:
description: External reference.
"#io-channel-cells":
const: 1
dependencies:
spi-cpol: [ spi-cpha ]
spi-cpha: [ spi-cpol ]
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "microchip,mcp3002";
reg = <0>;
vref-supply = <&vref_reg>;
spi-cpha;
spi-cpol;
#io-channel-cells = <1>;
};
adc@1 {
compatible = "microchip,mcp3002";
reg = <1>;
vref-supply = <&vref_reg>;
spi-max-frequency = <1500000>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,adc0832.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADC0832 and similar ADCs
maintainers:
- Akinobu Mita <akinobu.mita@gmail.com>
description: |
8 bit ADCs with 1, 2, 4 or 8 inputs for single ended or differential
conversion.
properties:
compatible:
enum:
- ti,adc0831
- ti,adc0832
- ti,adc0834
- ti,adc0838
reg:
maxItems: 1
spi-max-frequency: true
vref-supply:
description: External reference, needed to establish input scaling
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,adc0832";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <200000>;
#io-channel-cells = <1>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,adc108s102.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADC108S102 and ADC128S102
maintainers:
- Bogdan Pricop <bogdan.pricop@emutex.com>
description: |
Family of 8 channel, 10/12 bit, SPI, single ended ADCs.
properties:
compatible:
const:
ti,adc108s102
reg: true
vref-supply: true
spi-max-frequency: true
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
spi {
#address-cells= <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,adc108s102";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
#io-channel-cells = <1>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,adc128s052.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADC128S052 and similar ADCs
maintainers:
- Angelo Compagnucci <angelo.compagnucci@gmail.com>
description: |
Family of 12 bit SPI ADCs with 2 to 8 channels with a range of different
target sample rates.
properties:
compatible:
enum:
- ti,adc122s021
- ti,adc122s051
- ti,adc122s101
- ti,adc124s021
- ti,adc124s051
- ti,adc124s101
- ti,adc128s052
reg:
maxItems: 1
spi-max-frequency: true
vref-supply: true
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,adc128s052";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
#io-channel-cells = <1>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,adc161s626.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADC141S626 and ADC161S626 ADCs
maintainers:
- Matt Ranostay <matt.ranostay@konsulko.com>
description: |
Single channel 14/16bit differential ADCs
properties:
compatible:
enum:
- ti,adc141s626
- ti,adc161s626
reg:
maxItems: 1
spi-max-frequency: true
vdda-supply: true
"#io-channel-cells":
const: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,adc161s626";
vdda-supply = <&vdda_fixed>;
reg = <0>;
spi-max-frequency = <4300000>;
#io-channel-cells = <1>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,ads8344.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADS8344 ADC
maintainers:
- Gregory Clement <gregory.clement@bootlin.com>
description: |
16bit 8-channel ADC with single ended inputs.
properties:
compatible:
const: ti,ads8344
reg:
maxItems: 1
spi-max-frequency: true
vref-supply:
description: Supply the 2.5V or 5V reference voltage
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,ads8344";
reg = <0>;
vref-supply = <&refin_supply>;
spi-max-frequency = <10000000>;
#io-channel-cells = <1>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/ti,tlc4541.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments TLC4541 and similar ADCs
maintainers:
- Phil Reid <preid@electromag.com.au>
description: |
14/16bit single channel ADC with SPI interface.
properties:
compatible:
enum:
- ti,tlc3541
- ti,tlc4541
reg:
maxItems: 1
spi-max-frequency: true
vref-supply: true
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "ti,tlc4541";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <200000>;
#io-channel-cells = <1>;
};
};
...
* Texas Instruments' ADC0831/ADC0832/ADC0832/ADC0838
Required properties:
- compatible: Should be one of
* "ti,adc0831"
* "ti,adc0832"
* "ti,adc0834"
* "ti,adc0838"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
- spi-max-frequency: Max SPI frequency to use (< 400000)
Example:
adc@0 {
compatible = "ti,adc0832";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <200000>;
};
* Texas Instruments' ADC108S102 and ADC128S102 ADC chip
Required properties:
- compatible: Should be "ti,adc108s102"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc108s102";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
};
* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
Required properties:
- compatible: Should be one of:
- "ti,adc128s052"
- "ti,adc122s021"
- "ti,adc122s051"
- "ti,adc122s101"
- "ti,adc124s021"
- "ti,adc124s051"
- "ti,adc124s101"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc128s052";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
};
* Texas Instruments ADC141S626 and ADC161S626 chips
Required properties:
- compatible: Should be "ti,adc141s626" or "ti,adc161s626"
- reg: spi chip select number for the device
- vdda-supply: supply voltage to VDDA pin
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc161s626";
vdda-supply = <&vdda_fixed>;
reg = <0>;
spi-max-frequency = <4300000>;
};
* Texas Instruments ADS8344 A/DC chip
Required properties:
- compatible: Must be "ti,ads8344"
- reg: SPI chip select number for the device
- vref-supply: phandle to a regulator node that supplies the
reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,ads8344";
reg = <0>;
vref-supply = <&refin_supply>;
spi-max-frequency = <10000000>;
};
......@@ -19,6 +19,8 @@ description: |
http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_oem/RTD_oem_datasheet.pdf
http://www.atlas-scientific.com/_files/_datasheets/_probe/EZO_CO2_Datasheet.pdf
https://www.atlas-scientific.com/files/EZO_O2_datasheet.pdf
https://www.atlas-scientific.com/files/EZO_HUM_Datasheet.pdf
properties:
compatible:
......@@ -29,6 +31,8 @@ properties:
- atlas,ph-sm
- atlas,rtd-sm
- atlas,co2-ezo
- atlas,o2-ezo
- atlas,hum-ezo
reg:
maxItems: 1
......
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: "http://devicetree.org/schemas/iio/dac/lltc,ltc2632.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Linear Technology LTC263x 12-/10-/8-Bit Rail-to-Rail DAC
maintainers:
- Michael Hennerich <michael.hennerich@analog.com>
description: |
Bindings for the Linear Technology LTC2632/2634/2636 DAC
Datasheet can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/LTC263[246].pdf
properties:
compatible:
enum:
- lltc,ltc2632-l12
- lltc,ltc2632-l10
- lltc,ltc2632-l8
- lltc,ltc2632-h12
- lltc,ltc2632-h10
- lltc,ltc2632-h8
- lltc,ltc2634-l12
- lltc,ltc2634-l10
- lltc,ltc2634-l8
- lltc,ltc2634-h12
- lltc,ltc2634-h10
- lltc,ltc2634-h8
- lltc,ltc2636-l12
- lltc,ltc2636-l10
- lltc,ltc2636-l8
- lltc,ltc2636-h12
- lltc,ltc2636-h10
- lltc,ltc2636-h8
reg:
maxItems: 1
spi-max-frequency:
maximum: 2000000
vref-supply:
description:
Phandle to the external reference voltage supply. This should
only be set if there is an external reference voltage connected to the VREF
pin. If the property is not set the internal reference is used.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
vref: regulator-vref {
compatible = "regulator-fixed";
regulator-name = "vref-ltc2632";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <1250000>;
regulator-always-on;
};
spi {
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "lltc,ltc2632";
reg = <0>; /* CS0 */
spi-max-frequency = <1000000>;
vref-supply = <&vref>;
};
};
...
Linear Technology LTC2632/2634/2636 DAC
Required properties:
- compatible: Has to contain one of the following:
lltc,ltc2632-l12
lltc,ltc2632-l10
lltc,ltc2632-l8
lltc,ltc2632-h12
lltc,ltc2632-h10
lltc,ltc2632-h8
lltc,ltc2634-l12
lltc,ltc2634-l10
lltc,ltc2634-l8
lltc,ltc2634-h12
lltc,ltc2634-h10
lltc,ltc2634-h8
lltc,ltc2636-l12
lltc,ltc2636-l10
lltc,ltc2636-l8
lltc,ltc2636-h12
lltc,ltc2636-h10
lltc,ltc2636-h8
Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
apply. In particular, "reg" and "spi-max-frequency" properties must be given.
Optional properties:
- vref-supply: Phandle to the external reference voltage supply. This should
only be set if there is an external reference voltage connected to the VREF
pin. If the property is not set the internal reference is used.
Example:
vref: regulator-vref {
compatible = "regulator-fixed";
regulator-name = "vref-ltc2632";
regulator-min-microvolt = <1250000>;
regulator-max-microvolt = <1250000>;
regulator-always-on;
};
spi_master {
dac: ltc2632@0 {
compatible = "lltc,ltc2632-l12";
reg = <0>; /* CS0 */
spi-max-frequency = <1000000>;
vref-supply = <&vref>; /* optional */
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2020 Analog Devices Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/gyroscope/adi,adxrs290.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADXRS290 Dual-Axis MEMS Gyroscope
maintainers:
- Nishant Malpani <nish.malpani25@gmail.com>
description: |
Bindings for the Analog Devices ADXRS290 dual-axis MEMS gyroscope device.
https://www.analog.com/media/en/technical-documentation/data-sheets/ADXRS290.pdf
properties:
compatible:
const: adi,adxrs290
reg:
maxItems: 1
spi-max-frequency:
maximum: 5000000
spi-cpol: true
spi-cpha: true
required:
- compatible
- reg
- spi-max-frequency
- spi-cpol
- spi-cpha
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
gyro@0 {
compatible = "adi,adxrs290";
reg = <0>;
spi-max-frequency = <5000000>;
spi-cpol;
spi-cpha;
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/humidity/ti,hdc2010.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: HDC2010/HDC2080 humidity and temperature iio sensors
maintainers:
- Eugene Zaikonnikov <ez@norophonic.com>
description: |
Relative humidity and tempereature sensors on I2C bus
Datasheets are available at:
http://www.ti.com/product/HDC2010/datasheet
http://www.ti.com/product/HDC2080/datasheet
properties:
compatible:
enum:
- ti,hdc2010
- ti,hdc2080
vdd-supply:
maxItems: 1
reg:
maxItems: 1
required:
- compatible
- reg
examples:
- |
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
humidity@40 {
compatible = "ti,hdc2010";
reg = <0x40>;
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/ams,as73211.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
maintainers:
- Christian Eggers <ceggers@arri.de>
description: |
XYZ True Color Sensor with I2C Interface
https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf/a65474c0-b302-c2fd-e30a-c98df87616df
properties:
compatible:
enum:
- ams,as73211
reg:
description:
I2C address of the device (0x74...0x77).
maxItems: 1
interrupts:
description:
Interrupt specifier for the READY interrupt generated by the device.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
as73211@74 {
compatible = "ams,as73211";
reg = <0x74>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_color_sensor>;
interrupt-parent = <&gpio2>;
interrupts = <19 IRQ_TYPE_EDGE_RISING>; /* READY */
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/semtech,sx9310.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Semtech's SX9310 capacitive proximity sensor
maintainers:
- Daniel Campello <campello@chromium.org>
description: |
Semtech's SX9310/SX9311 capacitive proximity/button solution.
Specifications about the devices can be found at:
https://www.semtech.com/products/smart-sensing/sar-sensors/sx9310
properties:
compatible:
enum:
- semtech,sx9310
- semtech,sx9311
reg:
maxItems: 1
interrupts:
description:
The sole interrupt generated by the device used to announce the
preceding reading request has finished and that data is
available or that a close/far proximity event has happened.
maxItems: 1
vdd-supply:
description: Main power supply
svdd-supply:
description: Host interface power supply
"#io-channel-cells":
const: 1
required:
- compatible
- reg
- "#io-channel-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
proximity@28 {
compatible = "semtech,sx9310";
reg = <0x28>;
interrupt-parent = <&pio>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW 5>;
vdd-supply = <&pp3300_a>;
svdd-supply = <&pp1800_prox>;
#io-channel-cells = <1>;
};
};
......@@ -128,6 +128,22 @@ properties:
- mcube,mc3230
# MEMSIC 2-axis 8-bit digital accelerometer
- memsic,mxc6225
# Microchip differential I2C ADC, 1 Channel, 18 bit
- microchip,mcp3421
# Microchip differential I2C ADC, 2 Channel, 18 bit
- microchip,mcp3422
# Microchip differential I2C ADC, 2 Channel, 18 bit
- microchip,mcp3423
# Microchip differential I2C ADC, 4 Channel, 18 bit
- microchip,mcp3424
# Microchip differential I2C ADC, 1 Channel, 16 bit
- microchip,mcp3425
# Microchip differential I2C ADC, 2 Channel, 16 bit
- microchip,mcp3426
# Microchip differential I2C ADC, 2 Channel, 16 bit
- microchip,mcp3427
# Microchip differential I2C ADC, 4 Channel, 16 bit
- microchip,mcp3428
# Microchip 7-bit Single I2C Digital POT (5k)
- microchip,mcp4017-502
# Microchip 7-bit Single I2C Digital POT (10k)
......
......@@ -943,6 +943,13 @@ S: Supported
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
F: drivers/net/ethernet/amd/xgbe/
AMS AS73211 DRIVER
M: Christian Eggers <ceggers@arri.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/light/ams,as73211.yaml
F: drivers/iio/light/as73211.c
ANALOG DEVICES INC AD5686 DRIVER
M: Michael Hennerich <Michael.Hennerich@analog.com>
L: linux-pm@vger.kernel.org
......@@ -1108,6 +1115,13 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/adv7842*
ANALOG DEVICES INC ADXRS290 DRIVER
M: Nishant Malpani <nish.malpani25@gmail.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/gyro/adxrs290.c
F: Documentation/devicetree/bindings/iio/gyroscope/adi,adxrs290.yaml
ANALOG DEVICES INC ASOC CODEC DRIVERS
M: Lars-Peter Clausen <lars@metafoo.de>
M: Nuno Sá <nuno.sa@analog.com>
......
......@@ -5,6 +5,7 @@
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
......@@ -113,6 +114,11 @@
#define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1)
#define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1)
/* ADXL372_STATUS_2 */
#define ADXL372_STATUS_2_INACT(x) (((x) >> 4) & 0x1)
#define ADXL372_STATUS_2_ACT(x) (((x) >> 5) & 0x1)
#define ADXL372_STATUS_2_AC2(x) (((x) >> 6) & 0x1)
/* ADXL372_INT1_MAP */
#define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0)
#define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0)
......@@ -131,8 +137,17 @@
#define ADXL372_INT1_MAP_LOW_MSK BIT(7)
#define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7)
/* ADX372_THRESH */
#define ADXL372_THRESH_VAL_H_MSK GENMASK(10, 3)
#define ADXL372_THRESH_VAL_H_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_H_MSK, x)
#define ADXL372_THRESH_VAL_L_MSK GENMASK(2, 0)
#define ADXL372_THRESH_VAL_L_SEL(x) FIELD_GET(ADXL372_THRESH_VAL_L_MSK, x)
/* The ADXL372 includes a deep, 512 sample FIFO buffer */
#define ADXL372_FIFO_SIZE 512
#define ADXL372_X_AXIS_EN(x) ((x) & BIT(0))
#define ADXL372_Y_AXIS_EN(x) ((x) & BIT(1))
#define ADXL372_Z_AXIS_EN(x) ((x) & BIT(2))
/*
* At +/- 200g with 12-bit resolution, scale is computed as:
......@@ -222,6 +237,20 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
{ BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO },
};
static const struct iio_event_spec adxl372_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE),
}, {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
.mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD) | BIT(IIO_EV_INFO_ENABLE),
},
};
#define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
......@@ -239,6 +268,8 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
.shift = 4, \
.endianness = IIO_BE, \
}, \
.event_spec = adxl372_events, \
.num_event_specs = ARRAY_SIZE(adxl372_events) \
}
static const struct iio_chan_spec adxl372_channels[] = {
......@@ -252,8 +283,10 @@ struct adxl372_state {
struct device *dev;
struct regmap *regmap;
struct iio_trigger *dready_trig;
struct iio_trigger *peak_datardy_trig;
enum adxl372_fifo_mode fifo_mode;
enum adxl372_fifo_format fifo_format;
unsigned int fifo_axis_mask;
enum adxl372_op_mode op_mode;
enum adxl372_act_proc_mode act_proc_mode;
enum adxl372_odr odr;
......@@ -261,10 +294,12 @@ struct adxl372_state {
u32 act_time_ms;
u32 inact_time_ms;
u8 fifo_set_size;
u8 int1_bitmask;
u8 int2_bitmask;
unsigned long int1_bitmask;
unsigned long int2_bitmask;
u16 watermark;
__be16 fifo_buf[ADXL372_FIFO_SIZE];
bool peak_fifo_mode_en;
struct mutex threshold_m; /* lock for threshold */
};
static const unsigned long adxl372_channel_masks[] = {
......@@ -276,6 +311,46 @@ static const unsigned long adxl372_channel_masks[] = {
0
};
static ssize_t adxl372_read_threshold_value(struct iio_dev *indio_dev, unsigned int addr,
u16 *threshold)
{
struct adxl372_state *st = iio_priv(indio_dev);
__be16 raw_regval;
u16 regval;
int ret;
ret = regmap_bulk_read(st->regmap, addr, &raw_regval, sizeof(raw_regval));
if (ret < 0)
return ret;
regval = be16_to_cpu(raw_regval);
regval >>= 5;
*threshold = regval;
return 0;
}
static ssize_t adxl372_write_threshold_value(struct iio_dev *indio_dev, unsigned int addr,
u16 threshold)
{
struct adxl372_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->threshold_m);
ret = regmap_write(st->regmap, addr, ADXL372_THRESH_VAL_H_SEL(threshold));
if (ret < 0)
goto unlock;
ret = regmap_update_bits(st->regmap, addr + 1, GENMASK(7, 5),
ADXL372_THRESH_VAL_L_SEL(threshold) << 5);
unlock:
mutex_unlock(&st->threshold_m);
return ret;
}
static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
{
__be16 regval;
......@@ -453,8 +528,8 @@ static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
}
static int adxl372_set_interrupts(struct adxl372_state *st,
unsigned char int1_bitmask,
unsigned char int2_bitmask)
unsigned long int1_bitmask,
unsigned long int2_bitmask)
{
int ret;
......@@ -523,6 +598,39 @@ static int adxl372_get_status(struct adxl372_state *st,
return ret;
}
static void adxl372_arrange_axis_data(struct adxl372_state *st, __be16 *sample)
{
__be16 axis_sample[3];
int i = 0;
memset(axis_sample, 0, 3 * sizeof(__be16));
if (ADXL372_X_AXIS_EN(st->fifo_axis_mask))
axis_sample[i++] = sample[0];
if (ADXL372_Y_AXIS_EN(st->fifo_axis_mask))
axis_sample[i++] = sample[1];
if (ADXL372_Z_AXIS_EN(st->fifo_axis_mask))
axis_sample[i++] = sample[2];
memcpy(sample, axis_sample, 3 * sizeof(__be16));
}
static void adxl372_push_event(struct iio_dev *indio_dev, s64 timestamp, u8 status2)
{
unsigned int ev_dir = IIO_EV_DIR_NONE;
if (ADXL372_STATUS_2_ACT(status2))
ev_dir = IIO_EV_DIR_RISING;
if (ADXL372_STATUS_2_INACT(status2))
ev_dir = IIO_EV_DIR_FALLING;
if (ev_dir != IIO_EV_DIR_NONE)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_THRESH, ev_dir),
timestamp);
}
static irqreturn_t adxl372_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
......@@ -536,6 +644,8 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p)
if (ret < 0)
goto err;
adxl372_push_event(indio_dev, iio_get_time_ns(indio_dev), status2);
if (st->fifo_mode != ADXL372_FIFO_BYPASSED &&
ADXL372_STATUS_1_FIFO_FULL(status1)) {
/*
......@@ -554,8 +664,12 @@ static irqreturn_t adxl372_trigger_handler(int irq, void *p)
goto err;
/* Each sample is 2 bytes */
for (i = 0; i < fifo_entries; i += st->fifo_set_size)
for (i = 0; i < fifo_entries; i += st->fifo_set_size) {
/* filter peak detection data */
if (st->peak_fifo_mode_en)
adxl372_arrange_axis_data(st, &st->fifo_buf[i]);
iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
}
}
err:
iio_trigger_notify_done(indio_dev->trig);
......@@ -723,6 +837,129 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
}
}
static int adxl372_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_direction dir,
enum iio_event_info info, int *val, int *val2)
{
struct adxl372_state *st = iio_priv(indio_dev);
unsigned int addr;
u16 raw_value;
int ret;
switch (info) {
case IIO_EV_INFO_VALUE:
switch (dir) {
case IIO_EV_DIR_RISING:
addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index;
ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value);
if (ret < 0)
return ret;
*val = raw_value * ADXL372_USCALE;
*val2 = 1000000;
return IIO_VAL_FRACTIONAL;
case IIO_EV_DIR_FALLING:
addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index;
ret = adxl372_read_threshold_value(indio_dev, addr, &raw_value);
if (ret < 0)
return ret;
*val = raw_value * ADXL372_USCALE;
*val2 = 1000000;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
case IIO_EV_INFO_PERIOD:
switch (dir) {
case IIO_EV_DIR_RISING:
*val = st->act_time_ms;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case IIO_EV_DIR_FALLING:
*val = st->inact_time_ms;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int adxl372_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_direction dir,
enum iio_event_info info, int val, int val2)
{
struct adxl372_state *st = iio_priv(indio_dev);
unsigned int val_ms;
unsigned int addr;
u16 raw_val;
switch (info) {
case IIO_EV_INFO_VALUE:
raw_val = DIV_ROUND_UP(val * 1000000, ADXL372_USCALE);
switch (dir) {
case IIO_EV_DIR_RISING:
addr = ADXL372_X_THRESH_ACT_H + 2 * chan->scan_index;
return adxl372_write_threshold_value(indio_dev, addr, raw_val);
case IIO_EV_DIR_FALLING:
addr = ADXL372_X_THRESH_INACT_H + 2 * chan->scan_index;
return adxl372_write_threshold_value(indio_dev, addr, raw_val);
default:
return -EINVAL;
}
case IIO_EV_INFO_PERIOD:
val_ms = val * 1000 + DIV_ROUND_UP(val2, 1000);
switch (dir) {
case IIO_EV_DIR_RISING:
return adxl372_set_activity_time_ms(st, val_ms);
case IIO_EV_DIR_FALLING:
return adxl372_set_inactivity_time_ms(st, val_ms);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int adxl372_read_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_direction dir)
{
struct adxl372_state *st = iio_priv(indio_dev);
switch (dir) {
case IIO_EV_DIR_RISING:
return FIELD_GET(ADXL372_INT1_MAP_ACT_MSK, st->int1_bitmask);
case IIO_EV_DIR_FALLING:
return FIELD_GET(ADXL372_INT1_MAP_INACT_MSK, st->int1_bitmask);
default:
return -EINVAL;
}
}
static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct iio_chan_spec *chan,
enum iio_event_type type, enum iio_event_direction dir,
int state)
{
struct adxl372_state *st = iio_priv(indio_dev);
switch (dir) {
case IIO_EV_DIR_RISING:
set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_ACT_MSK,
ADXL372_INT1_MAP_ACT_MODE(state));
break;
case IIO_EV_DIR_FALLING:
set_mask_bits(&st->int1_bitmask, ADXL372_INT1_MAP_INACT_MSK,
ADXL372_INT1_MAP_INACT_MODE(state));
break;
default:
return -EINVAL;
}
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
}
static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
......@@ -795,7 +1032,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
unsigned int mask;
int i, ret;
ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK;
ret = adxl372_set_interrupts(st, st->int1_bitmask, 0);
if (ret < 0)
return ret;
......@@ -810,13 +1048,22 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
return -EINVAL;
st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
st->fifo_axis_mask = adxl372_axis_lookup_table[i].bits;
st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
/* Configure the FIFO to store sets of impact event peak. */
if (st->peak_fifo_mode_en) {
st->fifo_set_size = 3;
st->fifo_format = ADXL372_XYZ_PEAK_FIFO;
}
/*
* The 512 FIFO samples can be allotted in several ways, such as:
* 170 sample sets of concurrent 3-axis data
* 256 sample sets of concurrent 2-axis data (user selectable)
* 512 sample sets of single-axis data
* 170 sets of impact event peak (x, y, z)
*/
if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE)
st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size);
......@@ -826,7 +1073,8 @@ static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
ret = adxl372_configure_fifo(st);
if (ret < 0) {
st->fifo_mode = ADXL372_FIFO_BYPASSED;
adxl372_set_interrupts(st, 0, 0);
st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK;
adxl372_set_interrupts(st, st->int1_bitmask, 0);
return ret;
}
......@@ -837,7 +1085,8 @@ static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
{
struct adxl372_state *st = iio_priv(indio_dev);
adxl372_set_interrupts(st, 0, 0);
st->int1_bitmask &= ~ADXL372_INT1_MAP_FIFO_FULL_MSK;
adxl372_set_interrupts(st, st->int1_bitmask, 0);
st->fifo_mode = ADXL372_FIFO_BYPASSED;
adxl372_configure_fifo(st);
......@@ -854,12 +1103,11 @@ static int adxl372_dready_trig_set_state(struct iio_trigger *trig,
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct adxl372_state *st = iio_priv(indio_dev);
unsigned long int mask = 0;
if (state)
mask = ADXL372_INT1_MAP_FIFO_FULL_MSK;
st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK;
return adxl372_set_interrupts(st, mask, 0);
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
}
static int adxl372_validate_trigger(struct iio_dev *indio_dev,
......@@ -867,7 +1115,7 @@ static int adxl372_validate_trigger(struct iio_dev *indio_dev,
{
struct adxl372_state *st = iio_priv(indio_dev);
if (st->dready_trig != trig)
if (st->dready_trig != trig && st->peak_datardy_trig != trig)
return -EINVAL;
return 0;
......@@ -878,6 +1126,25 @@ static const struct iio_trigger_ops adxl372_trigger_ops = {
.set_trigger_state = adxl372_dready_trig_set_state,
};
static int adxl372_peak_dready_trig_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct adxl372_state *st = iio_priv(indio_dev);
if (state)
st->int1_bitmask |= ADXL372_INT1_MAP_FIFO_FULL_MSK;
st->peak_fifo_mode_en = state;
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
}
static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = {
.validate_device = &iio_trigger_validate_own_device,
.set_trigger_state = adxl372_peak_dready_trig_set_state,
};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
0444, adxl372_show_filter_freq_avail, NULL, 0);
......@@ -897,6 +1164,10 @@ static const struct iio_info adxl372_info = {
.attrs = &adxl372_attrs_group,
.read_raw = adxl372_read_raw,
.write_raw = adxl372_write_raw,
.read_event_config = adxl372_read_event_config,
.write_event_config = adxl372_write_event_config,
.read_event_value = adxl372_read_event_value,
.write_event_value = adxl372_write_event_value,
.debugfs_reg_access = &adxl372_reg_access,
.hwfifo_set_watermark = adxl372_set_watermark,
};
......@@ -925,6 +1196,8 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
st->regmap = regmap;
st->irq = irq;
mutex_init(&st->threshold_m);
indio_dev->channels = adxl372_channels;
indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
indio_dev->available_scan_masks = adxl372_channel_masks;
......@@ -955,13 +1228,27 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
if (st->dready_trig == NULL)
return -ENOMEM;
st->peak_datardy_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d-peak",
indio_dev->name,
indio_dev->id);
if (!st->peak_datardy_trig)
return -ENOMEM;
st->dready_trig->ops = &adxl372_trigger_ops;
st->peak_datardy_trig->ops = &adxl372_peak_data_trigger_ops;
st->dready_trig->dev.parent = dev;
st->peak_datardy_trig->dev.parent = dev;
iio_trigger_set_drvdata(st->dready_trig, indio_dev);
iio_trigger_set_drvdata(st->peak_datardy_trig, indio_dev);
ret = devm_iio_trigger_register(dev, st->dready_trig);
if (ret < 0)
return ret;
ret = devm_iio_trigger_register(dev, st->peak_datardy_trig);
if (ret < 0)
return ret;
indio_dev->trig = iio_trigger_get(st->dready_trig);
ret = devm_request_threaded_irq(dev, st->irq,
......
......@@ -6,6 +6,7 @@
*/
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
......@@ -46,9 +47,16 @@ static const struct i2c_device_id adxl372_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
static const struct of_device_id adxl372_of_match[] = {
{ .compatible = "adi,adxl372" },
{ }
};
MODULE_DEVICE_TABLE(of, adxl372_of_match);
static struct i2c_driver adxl372_i2c_driver = {
.driver = {
.name = "adxl372_i2c",
.of_match_table = adxl372_of_match,
},
.probe = adxl372_i2c_probe,
.id_table = adxl372_i2c_id,
......
......@@ -40,8 +40,8 @@ static const struct spi_device_id adxl372_spi_id[] = {
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
static const struct of_device_id adxl372_of_match[] = {
{ .compatible = "adi,adxl372" },
{ },
{ .compatible = "adi,adxl372" },
{ }
};
MODULE_DEVICE_TABLE(of, adxl372_of_match);
......
......@@ -1000,19 +1000,15 @@ static int bma180_probe(struct i2c_client *client,
return ret;
data->vdd_supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(data->vdd_supply)) {
if (PTR_ERR(data->vdd_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vdd regulator %d\n",
(int)PTR_ERR(data->vdd_supply));
return PTR_ERR(data->vdd_supply);
}
if (IS_ERR(data->vdd_supply))
return dev_err_probe(dev, PTR_ERR(data->vdd_supply),
"Failed to get vdd regulator\n");
data->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(data->vddio_supply)) {
if (PTR_ERR(data->vddio_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vddio regulator %d\n",
(int)PTR_ERR(data->vddio_supply));
return PTR_ERR(data->vddio_supply);
}
if (IS_ERR(data->vddio_supply))
return dev_err_probe(dev, PTR_ERR(data->vddio_supply),
"Failed to get vddio regulator\n");
/* Typical voltage 2.4V these are min and max */
ret = regulator_set_voltage(data->vdd_supply, 1620000, 3600000);
if (ret)
......
......@@ -2,16 +2,18 @@
/**
* BMA220 Digital triaxial acceleration sensor driver
*
* Copyright (c) 2016, Intel Corporation.
* Copyright (c) 2016,2020 Intel Corporation.
*/
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
......@@ -23,14 +25,13 @@
#define BMA220_REG_SUSPEND 0x18
#define BMA220_CHIP_ID 0xDD
#define BMA220_READ_MASK 0x80
#define BMA220_RANGE_MASK 0x03
#define BMA220_READ_MASK BIT(7)
#define BMA220_RANGE_MASK GENMASK(1, 0)
#define BMA220_DATA_SHIFT 2
#define BMA220_SUSPEND_SLEEP 0xFF
#define BMA220_SUSPEND_WAKE 0x00
#define BMA220_DEVICE_NAME "bma220"
#define BMA220_SCALE_AVAILABLE "0.623 1.248 2.491 4.983"
#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
......@@ -55,19 +56,8 @@ enum bma220_axis {
AXIS_Z,
};
static IIO_CONST_ATTR(in_accel_scale_available, BMA220_SCALE_AVAILABLE);
static struct attribute *bma220_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group bma220_attribute_group = {
.attrs = bma220_attributes,
};
static const int bma220_scale_table[][4] = {
{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}
static const int bma220_scale_table[][2] = {
{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000},
};
struct bma220_data {
......@@ -182,10 +172,26 @@ static int bma220_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
static int bma220_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*vals = (int *)bma220_scale_table;
*type = IIO_VAL_INT_PLUS_MICRO;
*length = ARRAY_SIZE(bma220_scale_table) * 2;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static const struct iio_info bma220_info = {
.read_raw = bma220_read_raw,
.write_raw = bma220_write_raw,
.attrs = &bma220_attribute_group,
.read_avail = bma220_read_avail,
};
static int bma220_init(struct spi_device *spi)
......@@ -198,10 +204,12 @@ static int bma220_init(struct spi_device *spi)
/* Make sure the chip is powered on */
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret == BMA220_SUSPEND_WAKE)
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret < 0)
return ret;
else if (ret == BMA220_SUSPEND_WAKE)
return bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret == BMA220_SUSPEND_WAKE)
return -EBUSY;
return 0;
}
......@@ -212,10 +220,12 @@ static int bma220_deinit(struct spi_device *spi)
/* Make sure the chip is powered off */
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret == BMA220_SUSPEND_SLEEP)
ret = bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret < 0)
return ret;
else if (ret == BMA220_SUSPEND_SLEEP)
return bma220_read_reg(spi, BMA220_REG_SUSPEND);
if (ret == BMA220_SUSPEND_SLEEP)
return -EBUSY;
return 0;
}
......@@ -245,7 +255,7 @@ static int bma220_probe(struct spi_device *spi)
indio_dev->available_scan_masks = bma220_accel_scan_masks;
ret = bma220_init(data->spi_device);
if (ret < 0)
if (ret)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
......@@ -278,56 +288,43 @@ static int bma220_remove(struct spi_device *spi)
return bma220_deinit(spi);
}
#ifdef CONFIG_PM_SLEEP
static int bma220_suspend(struct device *dev)
static __maybe_unused int bma220_suspend(struct device *dev)
{
struct bma220_data *data =
iio_priv(spi_get_drvdata(to_spi_device(dev)));
struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
/* The chip can be suspended/woken up by a simple register read. */
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
}
static int bma220_resume(struct device *dev)
static __maybe_unused int bma220_resume(struct device *dev)
{
struct bma220_data *data =
iio_priv(spi_get_drvdata(to_spi_device(dev)));
struct bma220_data *data = iio_priv(dev_get_drvdata(dev));
return bma220_read_reg(data->spi_device, BMA220_REG_SUSPEND);
}
static SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume);
#define BMA220_PM_OPS (&bma220_pm_ops)
#else
#define BMA220_PM_OPS NULL
#endif
static const struct spi_device_id bma220_spi_id[] = {
{"bma220", 0},
{}
};
#ifdef CONFIG_ACPI
static const struct acpi_device_id bma220_acpi_id[] = {
{"BMA0220", 0},
{}
};
MODULE_DEVICE_TABLE(spi, bma220_spi_id);
#endif
static struct spi_driver bma220_driver = {
.driver = {
.name = "bma220_spi",
.pm = BMA220_PM_OPS,
.acpi_match_table = ACPI_PTR(bma220_acpi_id),
.pm = &bma220_pm_ops,
.acpi_match_table = bma220_acpi_id,
},
.probe = bma220_probe,
.remove = bma220_remove,
.id_table = bma220_spi_id,
};
module_spi_driver(bma220_driver);
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
......
......@@ -1538,22 +1538,14 @@ static int mma8452_probe(struct i2c_client *client,
data->chip_info = match->data;
data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(data->vdd_reg)) {
if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "failed to get VDD regulator!\n");
return PTR_ERR(data->vdd_reg);
}
if (IS_ERR(data->vdd_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg),
"failed to get VDD regulator!\n");
data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
if (IS_ERR(data->vddio_reg)) {
if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "failed to get VDDIO regulator!\n");
return PTR_ERR(data->vddio_reg);
}
if (IS_ERR(data->vddio_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg),
"failed to get VDDIO regulator!\n");
ret = regulator_enable(data->vdd_reg);
if (ret) {
......
......@@ -340,7 +340,7 @@ config AXP288_ADC
config BCM_IPROC_ADC
tristate "Broadcom IPROC ADC driver"
depends on ARCH_BCM_IPROC || COMPILE_TEST
depends on (ARCH_BCM_IPROC && OF) || COMPILE_TEST
depends on MFD_SYSCON
default ARCH_BCM_CYGNUS
help
......
......@@ -276,7 +276,7 @@ static struct attribute *adi_axi_adc_attributes[] = {
static umode_t axi_adc_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adi_axi_adc_state *st = iio_priv(indio_dev);
struct adi_axi_adc_conv *conv = &st->client->conv;
......
......@@ -9,10 +9,10 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/thermal.h>
......@@ -67,7 +67,7 @@ struct axp_data;
struct axp20x_adc_iio {
struct regmap *regmap;
struct axp_data *data;
const struct axp_data *data;
};
enum axp20x_adc_channel_v {
......@@ -670,15 +670,15 @@ static int axp20x_probe(struct platform_device *pdev)
info->regmap = axp20x_dev->regmap;
indio_dev->modes = INDIO_DIRECT_MODE;
if (!pdev->dev.of_node) {
if (!dev_fwnode(&pdev->dev)) {
const struct platform_device_id *id;
id = platform_get_device_id(pdev);
info->data = (struct axp_data *)id->driver_data;
info->data = (const struct axp_data *)id->driver_data;
} else {
struct device *dev = &pdev->dev;
info->data = (struct axp_data *)of_device_get_match_data(dev);
info->data = device_get_match_data(dev);
}
indio_dev->name = platform_get_device_id(pdev)->name;
......@@ -742,7 +742,7 @@ static int axp20x_remove(struct platform_device *pdev)
static struct platform_driver axp20x_adc_driver = {
.driver = {
.name = "axp20x-adc",
.of_match_table = of_match_ptr(axp20x_adc_of_match),
.of_match_table = axp20x_adc_of_match,
},
.id_table = axp20x_adc_id_match,
.probe = axp20x_probe,
......
......@@ -4,7 +4,7 @@
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
......@@ -617,7 +617,7 @@ static struct platform_driver iproc_adc_driver = {
.remove = iproc_adc_remove,
.driver = {
.name = "iproc-static-adc",
.of_match_table = of_match_ptr(iproc_adc_of_match),
.of_match_table = iproc_adc_of_match,
},
};
module_platform_driver(iproc_adc_driver);
......
......@@ -348,11 +348,9 @@ static int envelope_detector_probe(struct platform_device *pdev)
indio_dev->num_channels = 1;
env->dac = devm_iio_channel_get(dev, "dac");
if (IS_ERR(env->dac)) {
if (PTR_ERR(env->dac) != -EPROBE_DEFER)
dev_err(dev, "failed to get dac input channel\n");
return PTR_ERR(env->dac);
}
if (IS_ERR(env->dac))
return dev_err_probe(dev, PTR_ERR(env->dac),
"failed to get dac input channel\n");
env->comp_irq = platform_get_irq_byname(pdev, "comp");
if (env->comp_irq < 0)
......@@ -360,11 +358,9 @@ static int envelope_detector_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, env->comp_irq, envelope_detector_comp_isr,
0, "envelope-detector", env);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to request interrupt\n");
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "failed to request interrupt\n");
env->comp_irq_trigger = irq_get_trigger_type(env->comp_irq);
if (env->comp_irq_trigger & IRQF_TRIGGER_RISING)
env->comp_irq_trigger_inv |= IRQF_TRIGGER_FALLING;
......
......@@ -844,13 +844,9 @@ static int exynos_adc_probe(struct platform_device *pdev)
}
info->vdd = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(info->vdd)) {
if (PTR_ERR(info->vdd) != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed getting regulator, err = %ld\n",
PTR_ERR(info->vdd));
return PTR_ERR(info->vdd);
}
if (IS_ERR(info->vdd))
return dev_err_probe(&pdev->dev, PTR_ERR(info->vdd),
"failed getting regulator");
ret = regulator_enable(info->vdd);
if (ret)
......
......@@ -180,13 +180,9 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
return ret;
ddata->ref = devm_regulator_get(dev, "vref");
if (IS_ERR(ddata->ref)) {
if (PTR_ERR(ddata->ref) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vref regulator: %pe\n",
ddata->ref);
return PTR_ERR(ddata->ref);
}
if (IS_ERR(ddata->ref))
return dev_err_probe(dev, PTR_ERR(ddata->ref),
"Failed to get vref regulator\n");
ret = regulator_enable(ddata->ref);
if (ret < 0) {
......
......@@ -719,11 +719,8 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
if (ret == -ENODEV)
return 0;
if (ret != -EPROBE_DEFER)
dev_err(indio_dev->dev.parent,
"failed to get temperature_calib cell\n");
return ret;
return dev_err_probe(indio_dev->dev.parent, ret,
"failed to get temperature_calib cell\n");
}
priv->tsc_regmap =
......
......@@ -495,12 +495,9 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
return PTR_ERR(priv->regs);
priv->clk = devm_clk_get(dev, "fck");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret);
return ret;
}
if (IS_ERR(priv->clk))
return dev_err_probe(dev, PTR_ERR(priv->clk),
"Failed to get IF clock\n");
ret = rcar_gyroadc_parse_subdevs(indio_dev);
if (ret)
......
......@@ -582,11 +582,9 @@ static int stm32_adc_core_switches_probe(struct device *dev,
priv->syscfg = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(priv->syscfg)) {
ret = PTR_ERR(priv->syscfg);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Can't probe syscfg: %d\n", ret);
return ret;
}
if (ret != -ENODEV)
return dev_err_probe(dev, ret, "Can't probe syscfg\n");
priv->syscfg = NULL;
}
......@@ -596,12 +594,9 @@ static int stm32_adc_core_switches_probe(struct device *dev,
priv->booster = devm_regulator_get_optional(dev, "booster");
if (IS_ERR(priv->booster)) {
ret = PTR_ERR(priv->booster);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "can't get booster %d\n",
ret);
return ret;
}
if (ret != -ENODEV)
dev_err_probe(dev, ret, "can't get booster\n");
priv->booster = NULL;
}
}
......@@ -612,11 +607,9 @@ static int stm32_adc_core_switches_probe(struct device *dev,
priv->vdd = devm_regulator_get_optional(dev, "vdd");
if (IS_ERR(priv->vdd)) {
ret = PTR_ERR(priv->vdd);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "can't get vdd %d\n", ret);
return ret;
}
if (ret != -ENODEV)
return dev_err_probe(dev, ret, "can't get vdd\n");
priv->vdd = NULL;
}
}
......@@ -669,42 +662,24 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->common.phys_base = res->start;
priv->vdda = devm_regulator_get(&pdev->dev, "vdda");
if (IS_ERR(priv->vdda)) {
ret = PTR_ERR(priv->vdda);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "vdda get failed, %d\n", ret);
return ret;
}
if (IS_ERR(priv->vdda))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->vdda),
"vdda get failed\n");
priv->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(priv->vref)) {
ret = PTR_ERR(priv->vref);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "vref get failed, %d\n", ret);
return ret;
}
priv->aclk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(priv->aclk)) {
ret = PTR_ERR(priv->aclk);
if (ret != -ENOENT) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
return ret;
}
priv->aclk = NULL;
}
priv->bclk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(priv->bclk)) {
ret = PTR_ERR(priv->bclk);
if (ret != -ENOENT) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
return ret;
}
priv->bclk = NULL;
}
if (IS_ERR(priv->vref))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->vref),
"vref get failed\n");
priv->aclk = devm_clk_get_optional(&pdev->dev, "adc");
if (IS_ERR(priv->aclk))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->aclk),
"Can't get 'adc' clock\n");
priv->bclk = devm_clk_get_optional(&pdev->dev, "bus");
if (IS_ERR(priv->bclk))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->bclk),
"Can't get 'bus' clock\n");
ret = stm32_adc_core_switches_probe(dev, priv);
if (ret)
......
......@@ -1805,13 +1805,9 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
adc->dma_chan = dma_request_chan(dev, "rx");
if (IS_ERR(adc->dma_chan)) {
ret = PTR_ERR(adc->dma_chan);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev,
"DMA channel request failed with %d\n",
ret);
return ret;
}
if (ret != -ENODEV)
return dev_err_probe(dev, ret,
"DMA channel request failed with\n");
/* DMA is optional: fall back to IRQ mode */
adc->dma_chan = NULL;
......
......@@ -1473,13 +1473,9 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
/* Optionally request DMA */
ret = stm32_dfsdm_dma_request(dev, indio_dev);
if (ret) {
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev,
"DMA channel request failed with %d\n",
ret);
return ret;
}
if (ret != -ENODEV)
return dev_err_probe(dev, ret,
"DMA channel request failed with\n");
dev_dbg(dev, "No DMA support\n");
return 0;
......
......@@ -243,12 +243,9 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
* on use case.
*/
priv->clk = devm_clk_get(&pdev->dev, "dfsdm");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Failed to get clock (%d)\n", ret);
return ret;
}
if (IS_ERR(priv->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
"Failed to get clock\n");
priv->aclk = devm_clk_get(&pdev->dev, "audio");
if (IS_ERR(priv->aclk))
......
......@@ -19,7 +19,6 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
......@@ -153,17 +152,7 @@ static int adc081c_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
if (ACPI_COMPANION(&client->dev)) {
const struct acpi_device_id *ad_id;
ad_id = acpi_match_device(client->dev.driver->acpi_match_table,
&client->dev);
if (!ad_id)
return -ENODEV;
model = &adcxx1c_models[ad_id->driver_data];
} else {
model = &adcxx1c_models[id->driver_data];
}
model = &adcxx1c_models[id->driver_data];
iio = devm_iio_device_alloc(&client->dev, sizeof(*adc));
if (!iio)
......@@ -238,21 +227,10 @@ static const struct of_device_id adc081c_of_match[] = {
};
MODULE_DEVICE_TABLE(of, adc081c_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id adc081c_acpi_match[] = {
{ "ADC081C", ADC081C },
{ "ADC101C", ADC101C },
{ "ADC121C", ADC121C },
{ }
};
MODULE_DEVICE_TABLE(acpi, adc081c_acpi_match);
#endif
static struct i2c_driver adc081c_driver = {
.driver = {
.name = "adc081c",
.of_match_table = adc081c_of_match,
.acpi_match_table = ACPI_PTR(adc081c_acpi_match),
},
.probe = adc081c_probe,
.remove = adc081c_remove,
......
......@@ -20,6 +20,7 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
......@@ -299,13 +300,11 @@ static int adc108s102_remove(struct spi_device *spi)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id adc108s102_of_match[] = {
{ .compatible = "ti,adc108s102" },
{ }
};
MODULE_DEVICE_TABLE(of, adc108s102_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id adc108s102_acpi_ids[] = {
......@@ -324,7 +323,7 @@ MODULE_DEVICE_TABLE(spi, adc108s102_id);
static struct spi_driver adc108s102_driver = {
.driver = {
.name = "adc108s102",
.of_match_table = of_match_ptr(adc108s102_of_match),
.of_match_table = adc108s102_of_match,
.acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
},
.probe = adc108s102_probe,
......
......@@ -13,6 +13,7 @@
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/iio/iio.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
......@@ -220,7 +221,7 @@ MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.of_match_table = of_match_ptr(adc128_of_match),
.of_match_table = adc128_of_match,
.acpi_match_table = ACPI_PTR(adc128_acpi_match),
},
.probe = adc128_probe,
......
......@@ -276,11 +276,9 @@ static int rescale_probe(struct platform_device *pdev)
int ret;
source = devm_iio_channel_get(dev, NULL);
if (IS_ERR(source)) {
if (PTR_ERR(source) != -EPROBE_DEFER)
dev_err(dev, "failed to get source channel\n");
return PTR_ERR(source);
}
if (IS_ERR(source))
return dev_err_probe(dev, PTR_ERR(source),
"failed to get source channel\n");
sizeof_ext_info = iio_get_channel_ext_info_count(source);
if (sizeof_ext_info) {
......
......@@ -18,6 +18,7 @@ config AD8366
AD8366 Dual-Digital Variable Gain Amplifier (VGA)
ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
ADL5240 Digitally controlled variable gain amplifier (VGA)
HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
To compile this driver as a module, choose M here: the
module will be called ad8366.
......
......@@ -201,12 +201,9 @@ static int hmc425a_probe(struct platform_device *pdev)
st->gain = st->chip_info->default_gain;
st->gpios = devm_gpiod_get_array(&pdev->dev, "ctrl", GPIOD_OUT_LOW);
if (IS_ERR(st->gpios)) {
ret = PTR_ERR(st->gpios);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get gpios\n");
return ret;
}
if (IS_ERR(st->gpios))
return dev_err_probe(&pdev->dev, PTR_ERR(st->gpios),
"failed to get gpios\n");
if (st->gpios->ndescs != st->chip_info->num_gpios) {
dev_err(&pdev->dev, "%d GPIOs needed to operate\n",
......
......@@ -45,7 +45,8 @@ static struct dmaengine_buffer *iio_buffer_to_dmaengine_buffer(
return container_of(buffer, struct dmaengine_buffer, queue.buffer);
}
static void iio_dmaengine_buffer_block_done(void *data)
static void iio_dmaengine_buffer_block_done(void *data,
const struct dmaengine_result *result)
{
struct iio_dma_buffer_block *block = data;
unsigned long flags;
......@@ -53,6 +54,7 @@ static void iio_dmaengine_buffer_block_done(void *data)
spin_lock_irqsave(&block->queue->list_lock, flags);
list_del(&block->head);
spin_unlock_irqrestore(&block->queue->list_lock, flags);
block->bytes_used -= result->residue;
iio_dma_buffer_block_done(block);
}
......@@ -74,7 +76,7 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
if (!desc)
return -ENOMEM;
desc->callback = iio_dmaengine_buffer_block_done;
desc->callback_result = iio_dmaengine_buffer_block_done;
desc->callback_param = block;
cookie = dmaengine_submit(desc);
......
......@@ -16,10 +16,13 @@
#include <linux/iio/iio.h>
#define ATLAS_EZO_DRV_NAME "atlas-ezo-sensor"
#define ATLAS_CO2_INT_TIME_IN_MS 950
#define ATLAS_INT_TIME_IN_MS 950
#define ATLAS_INT_HUM_TIME_IN_MS 350
enum {
ATLAS_CO2_EZO,
ATLAS_O2_EZO,
ATLAS_HUM_EZO,
};
struct atlas_ezo_device {
......@@ -38,15 +41,37 @@ struct atlas_ezo_data {
u8 buffer[8];
};
#define ATLAS_CONCENTRATION_CHANNEL(_modifier) \
{ \
.type = IIO_CONCENTRATION, \
.modified = 1,\
.channel2 = _modifier, \
.info_mask_separate = \
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = 0, \
.scan_type = { \
.sign = 'u', \
.realbits = 32, \
.storagebits = 32, \
.endianness = IIO_CPU, \
}, \
}
static const struct iio_chan_spec atlas_co2_ezo_channels[] = {
ATLAS_CONCENTRATION_CHANNEL(IIO_MOD_CO2),
};
static const struct iio_chan_spec atlas_o2_ezo_channels[] = {
ATLAS_CONCENTRATION_CHANNEL(IIO_MOD_O2),
};
static const struct iio_chan_spec atlas_hum_ezo_channels[] = {
{
.type = IIO_CONCENTRATION,
.modified = 1,
.channel2 = IIO_MOD_CO2,
.type = IIO_HUMIDITYRELATIVE,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.scan_type = {
.sign = 'u',
.realbits = 32,
.storagebits = 32,
......@@ -59,10 +84,30 @@ static struct atlas_ezo_device atlas_ezo_devices[] = {
[ATLAS_CO2_EZO] = {
.channels = atlas_co2_ezo_channels,
.num_channels = 1,
.delay = ATLAS_CO2_INT_TIME_IN_MS,
.delay = ATLAS_INT_TIME_IN_MS,
},
[ATLAS_O2_EZO] = {
.channels = atlas_o2_ezo_channels,
.num_channels = 1,
.delay = ATLAS_INT_TIME_IN_MS,
},
[ATLAS_HUM_EZO] = {
.channels = atlas_hum_ezo_channels,
.num_channels = 1,
.delay = ATLAS_INT_HUM_TIME_IN_MS,
},
};
static void atlas_ezo_sanitize(char *buf)
{
char *ptr = strchr(buf, '.');
if (!ptr)
return;
memmove(ptr, ptr + 1, strlen(ptr));
}
static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
......@@ -96,6 +141,9 @@ static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
return -EBUSY;
}
/* removing floating point for fixed number representation */
atlas_ezo_sanitize(data->buffer + 2);
ret = kstrtol(data->buffer + 1, 10, &tmp);
*val = tmp;
......@@ -105,9 +153,27 @@ static int atlas_ezo_read_raw(struct iio_dev *indio_dev,
return ret ? ret : IIO_VAL_INT;
}
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = 100; /* 0.0001 */
return IIO_VAL_INT_PLUS_MICRO;
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
*val = 10;
return IIO_VAL_INT;
case IIO_CONCENTRATION:
break;
default:
return -EINVAL;
}
/* IIO_CONCENTRATION modifiers */
switch (chan->channel2) {
case IIO_MOD_CO2:
*val = 0;
*val2 = 100; /* 0.0001 */
return IIO_VAL_INT_PLUS_MICRO;
case IIO_MOD_O2:
*val = 100;
return IIO_VAL_INT;
}
return -EINVAL;
}
return 0;
......@@ -119,12 +185,16 @@ static const struct iio_info atlas_info = {
static const struct i2c_device_id atlas_ezo_id[] = {
{ "atlas-co2-ezo", ATLAS_CO2_EZO },
{ "atlas-o2-ezo", ATLAS_O2_EZO },
{ "atlas-hum-ezo", ATLAS_HUM_EZO },
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_ezo_id);
static const struct of_device_id atlas_ezo_dt_ids[] = {
{ .compatible = "atlas,co2-ezo", .data = (void *)ATLAS_CO2_EZO, },
{ .compatible = "atlas,o2-ezo", .data = (void *)ATLAS_O2_EZO, },
{ .compatible = "atlas,hum-ezo", .data = (void *)ATLAS_HUM_EZO, },
{}
};
MODULE_DEVICE_TABLE(of, atlas_ezo_dt_ids);
......
......@@ -705,13 +705,8 @@ int scd30_probe(struct device *dev, int irq, const char *name, void *priv,
indio_dev->available_scan_masks = scd30_scan_masks;
state->vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(state->vdd)) {
if (PTR_ERR(state->vdd) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(dev, "failed to get regulator\n");
return PTR_ERR(state->vdd);
}
if (IS_ERR(state->vdd))
return dev_err_probe(dev, PTR_ERR(state->vdd), "failed to get regulator\n");
ret = regulator_enable(state->vdd);
if (ret)
......
......@@ -206,12 +206,12 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
}
#define DECLARE_AD5693_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
}
#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 1, bits, _shift), \
AD5868_CHANNEL(1, 2, bits, _shift), \
AD5868_CHANNEL(2, 4, bits, _shift), \
......@@ -219,7 +219,7 @@ static struct iio_chan_spec name[] = { \
}
#define DECLARE_AD5676_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
AD5868_CHANNEL(1, 1, bits, _shift), \
AD5868_CHANNEL(2, 2, bits, _shift), \
......@@ -231,7 +231,7 @@ static struct iio_chan_spec name[] = { \
}
#define DECLARE_AD5679_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
static const struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
AD5868_CHANNEL(1, 1, bits, _shift), \
AD5868_CHANNEL(2, 2, bits, _shift), \
......
......@@ -104,7 +104,7 @@ typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
struct ad5686_chip_info {
u16 int_vref_mv;
unsigned int num_channels;
struct iio_chan_spec *channels;
const struct iio_chan_spec *channels;
enum ad5686_regmap_type regmap_type;
};
......
......@@ -183,18 +183,14 @@ static int dpot_dac_probe(struct platform_device *pdev)
indio_dev->num_channels = 1;
dac->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(dac->vref)) {
if (PTR_ERR(dac->vref) != -EPROBE_DEFER)
dev_err(&pdev->dev, "failed to get vref regulator\n");
return PTR_ERR(dac->vref);
}
if (IS_ERR(dac->vref))
return dev_err_probe(&pdev->dev, PTR_ERR(dac->vref),
"failed to get vref regulator\n");
dac->dpot = devm_iio_channel_get(dev, "dpot");
if (IS_ERR(dac->dpot)) {
if (PTR_ERR(dac->dpot) != -EPROBE_DEFER)
dev_err(dev, "failed to get dpot input channel\n");
return PTR_ERR(dac->dpot);
}
if (IS_ERR(dac->dpot))
return dev_err_probe(&pdev->dev, PTR_ERR(dac->dpot),
"failed to get dpot input channel\n");
ret = iio_get_channel_type(dac->dpot, &type);
if (ret < 0)
......
......@@ -150,10 +150,7 @@ static int stm32_dac_probe(struct platform_device *pdev)
rst = devm_reset_control_get_optional_exclusive(dev, NULL);
if (rst) {
if (IS_ERR(rst)) {
ret = PTR_ERR(rst);
if (ret != -EPROBE_DEFER)
dev_err(dev, "reset get failed, %d\n", ret);
ret = dev_err_probe(dev, PTR_ERR(rst), "reset get failed\n");
goto err_hw_stop;
}
......
......@@ -47,8 +47,8 @@ struct dac5571_data {
struct mutex lock;
struct regulator *vref;
u16 val[4];
bool powerdown;
u8 powerdown_mode;
bool powerdown[4];
u8 powerdown_mode[4];
struct dac5571_spec const *spec;
int (*dac5571_cmd)(struct dac5571_data *data, int channel, u16 val);
int (*dac5571_pwrdwn)(struct dac5571_data *data, int channel, u8 pwrdwn);
......@@ -125,7 +125,7 @@ static int dac5571_get_powerdown_mode(struct iio_dev *indio_dev,
{
struct dac5571_data *data = iio_priv(indio_dev);
return data->powerdown_mode;
return data->powerdown_mode[chan->channel];
}
static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev,
......@@ -135,17 +135,17 @@ static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev,
struct dac5571_data *data = iio_priv(indio_dev);
int ret = 0;
if (data->powerdown_mode == mode)
if (data->powerdown_mode[chan->channel] == mode)
return 0;
mutex_lock(&data->lock);
if (data->powerdown) {
if (data->powerdown[chan->channel]) {
ret = data->dac5571_pwrdwn(data, chan->channel,
DAC5571_POWERDOWN(mode));
if (ret)
goto out;
}
data->powerdown_mode = mode;
data->powerdown_mode[chan->channel] = mode;
out:
mutex_unlock(&data->lock);
......@@ -167,7 +167,7 @@ static ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev,
{
struct dac5571_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->powerdown);
return sprintf(buf, "%d\n", data->powerdown[chan->channel]);
}
static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev,
......@@ -183,19 +183,20 @@ static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev,
if (ret)
return ret;
if (data->powerdown == powerdown)
if (data->powerdown[chan->channel] == powerdown)
return len;
mutex_lock(&data->lock);
if (powerdown)
ret = data->dac5571_pwrdwn(data, chan->channel,
DAC5571_POWERDOWN(data->powerdown_mode));
DAC5571_POWERDOWN(data->powerdown_mode[chan->channel]));
else
ret = data->dac5571_cmd(data, chan->channel, data->val[0]);
ret = data->dac5571_cmd(data, chan->channel,
data->val[chan->channel]);
if (ret)
goto out;
data->powerdown = powerdown;
data->powerdown[chan->channel] = powerdown;
out:
mutex_unlock(&data->lock);
......@@ -209,9 +210,9 @@ static const struct iio_chan_spec_ext_info dac5571_ext_info[] = {
.name = "powerdown",
.read = dac5571_read_powerdown,
.write = dac5571_write_powerdown,
.shared = IIO_SHARED_BY_TYPE,
.shared = IIO_SEPARATE,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode),
IIO_ENUM("powerdown_mode", IIO_SEPARATE, &dac5571_powerdown_mode),
IIO_ENUM_AVAILABLE("powerdown_mode", &dac5571_powerdown_mode),
{},
};
......@@ -276,7 +277,7 @@ static int dac5571_write_raw(struct iio_dev *indio_dev,
if (val >= (1 << data->spec->resolution) || val < 0)
return -EINVAL;
if (data->powerdown)
if (data->powerdown[chan->channel])
return -EBUSY;
mutex_lock(&data->lock);
......
......@@ -969,6 +969,13 @@ static int ad9523_setup(struct iio_dev *indio_dev)
return 0;
}
static void ad9523_reg_disable(void *data)
{
struct regulator *reg = data;
regulator_disable(reg);
}
static int ad9523_probe(struct spi_device *spi)
{
struct ad9523_platform_data *pdata = spi->dev.platform_data;
......@@ -994,21 +1001,22 @@ static int ad9523_probe(struct spi_device *spi)
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = devm_add_action_or_reset(&spi->dev, ad9523_reg_disable,
st->reg);
if (ret)
return ret;
}
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(st->pwrdown_gpio)) {
ret = PTR_ERR(st->pwrdown_gpio);
goto error_disable_reg;
}
if (IS_ERR(st->pwrdown_gpio))
return PTR_ERR(st->pwrdown_gpio);
st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(st->reset_gpio)) {
ret = PTR_ERR(st->reset_gpio);
goto error_disable_reg;
}
if (IS_ERR(st->reset_gpio))
return PTR_ERR(st->reset_gpio);
if (st->reset_gpio) {
udelay(1);
......@@ -1017,10 +1025,8 @@ static int ad9523_probe(struct spi_device *spi)
st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync",
GPIOD_OUT_HIGH);
if (IS_ERR(st->sync_gpio)) {
ret = PTR_ERR(st->sync_gpio);
goto error_disable_reg;
}
if (IS_ERR(st->sync_gpio))
return PTR_ERR(st->sync_gpio);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
......@@ -1035,34 +1041,9 @@ static int ad9523_probe(struct spi_device *spi)
ret = ad9523_setup(indio_dev);
if (ret < 0)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_disable_reg;
dev_info(&spi->dev, "probed %s\n", indio_dev->name);
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
}
static int ad9523_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad9523_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
return 0;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad9523_id[] = {
......@@ -1076,7 +1057,6 @@ static struct spi_driver ad9523_driver = {
.name = "ad9523",
},
.probe = ad9523_probe,
.remove = ad9523_remove,
.id_table = ad9523_id,
};
module_spi_driver(ad9523_driver);
......
......@@ -41,6 +41,16 @@ config ADIS16260
This driver can also be built as a module. If so, the module
will be called adis16260.
config ADXRS290
tristate "Analog Devices ADXRS290 Dual-Axis MEMS Gyroscope SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices ADXRS290 programmable
digital output gyroscope.
This driver can also be built as a module. If so, the module will be
called adxrs290.
config ADXRS450
tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver"
depends on SPI
......
......@@ -8,6 +8,7 @@ obj-$(CONFIG_ADIS16080) += adis16080.o
obj-$(CONFIG_ADIS16130) += adis16130.o
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_ADIS16260) += adis16260.o
obj-$(CONFIG_ADXRS290) += adxrs290.o
obj-$(CONFIG_ADXRS450) += adxrs450.o
obj-$(CONFIG_BMG160) += bmg160_core.o
obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ADXRS290 SPI Gyroscope Driver
*
* Copyright (C) 2020 Nishant Malpani <nish.malpani25@gmail.com>
* Copyright (C) 2020 Analog Devices, Inc.
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define ADXRS290_ADI_ID 0xAD
#define ADXRS290_MEMS_ID 0x1D
#define ADXRS290_DEV_ID 0x92
#define ADXRS290_REG_ADI_ID 0x00
#define ADXRS290_REG_MEMS_ID 0x01
#define ADXRS290_REG_DEV_ID 0x02
#define ADXRS290_REG_REV_ID 0x03
#define ADXRS290_REG_SN0 0x04 /* Serial Number Registers, 4 bytes */
#define ADXRS290_REG_DATAX0 0x08 /* Roll Rate o/p Data Regs, 2 bytes */
#define ADXRS290_REG_DATAY0 0x0A /* Pitch Rate o/p Data Regs, 2 bytes */
#define ADXRS290_REG_TEMP0 0x0C
#define ADXRS290_REG_POWER_CTL 0x10
#define ADXRS290_REG_FILTER 0x11
#define ADXRS290_REG_DATA_RDY 0x12
#define ADXRS290_READ BIT(7)
#define ADXRS290_TSM BIT(0)
#define ADXRS290_MEASUREMENT BIT(1)
#define ADXRS290_SYNC GENMASK(1, 0)
#define ADXRS290_LPF_MASK GENMASK(2, 0)
#define ADXRS290_LPF(x) FIELD_PREP(ADXRS290_LPF_MASK, x)
#define ADXRS290_HPF_MASK GENMASK(7, 4)
#define ADXRS290_HPF(x) FIELD_PREP(ADXRS290_HPF_MASK, x)
#define ADXRS290_READ_REG(reg) (ADXRS290_READ | (reg))
#define ADXRS290_MAX_TRANSITION_TIME_MS 100
enum adxrs290_mode {
ADXRS290_MODE_STANDBY,
ADXRS290_MODE_MEASUREMENT,
};
struct adxrs290_state {
struct spi_device *spi;
/* Serialize reads and their subsequent processing */
struct mutex lock;
enum adxrs290_mode mode;
unsigned int lpf_3db_freq_idx;
unsigned int hpf_3db_freq_idx;
};
/*
* Available cut-off frequencies of the low pass filter in Hz.
* The integer part and fractional part are represented separately.
*/
static const int adxrs290_lpf_3db_freq_hz_table[][2] = {
[0] = {480, 0},
[1] = {320, 0},
[2] = {160, 0},
[3] = {80, 0},
[4] = {56, 600000},
[5] = {40, 0},
[6] = {28, 300000},
[7] = {20, 0},
};
/*
* Available cut-off frequencies of the high pass filter in Hz.
* The integer part and fractional part are represented separately.
*/
static const int adxrs290_hpf_3db_freq_hz_table[][2] = {
[0] = {0, 0},
[1] = {0, 11000},
[2] = {0, 22000},
[3] = {0, 44000},
[4] = {0, 87000},
[5] = {0, 175000},
[6] = {0, 350000},
[7] = {0, 700000},
[8] = {1, 400000},
[9] = {2, 800000},
[10] = {11, 300000},
};
static int adxrs290_get_rate_data(struct iio_dev *indio_dev, const u8 cmd, int *val)
{
struct adxrs290_state *st = iio_priv(indio_dev);
int ret = 0;
int temp;
mutex_lock(&st->lock);
temp = spi_w8r16(st->spi, cmd);
if (temp < 0) {
ret = temp;
goto err_unlock;
}
*val = temp;
err_unlock:
mutex_unlock(&st->lock);
return ret;
}
static int adxrs290_get_temp_data(struct iio_dev *indio_dev, int *val)
{
const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_TEMP0);
struct adxrs290_state *st = iio_priv(indio_dev);
int ret = 0;
int temp;
mutex_lock(&st->lock);
temp = spi_w8r16(st->spi, cmd);
if (temp < 0) {
ret = temp;
goto err_unlock;
}
/* extract lower 12 bits temperature reading */
*val = temp & 0x0FFF;
err_unlock:
mutex_unlock(&st->lock);
return ret;
}
static int adxrs290_get_3db_freq(struct iio_dev *indio_dev, u8 *val, u8 *val2)
{
const u8 cmd = ADXRS290_READ_REG(ADXRS290_REG_FILTER);
struct adxrs290_state *st = iio_priv(indio_dev);
int ret = 0;
short temp;
mutex_lock(&st->lock);
temp = spi_w8r8(st->spi, cmd);
if (temp < 0) {
ret = temp;
goto err_unlock;
}
*val = FIELD_GET(ADXRS290_LPF_MASK, temp);
*val2 = FIELD_GET(ADXRS290_HPF_MASK, temp);
err_unlock:
mutex_unlock(&st->lock);
return ret;
}
static int adxrs290_spi_write_reg(struct spi_device *spi, const u8 reg,
const u8 val)
{
u8 buf[2];
buf[0] = reg;
buf[1] = val;
return spi_write_then_read(spi, buf, ARRAY_SIZE(buf), NULL, 0);
}
static int adxrs290_find_match(const int (*freq_tbl)[2], const int n,
const int val, const int val2)
{
int i;
for (i = 0; i < n; i++) {
if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2)
return i;
}
return -EINVAL;
}
static int adxrs290_set_filter_freq(struct iio_dev *indio_dev,
const unsigned int lpf_idx,
const unsigned int hpf_idx)
{
struct adxrs290_state *st = iio_priv(indio_dev);
u8 val;
val = ADXRS290_HPF(hpf_idx) | ADXRS290_LPF(lpf_idx);
return adxrs290_spi_write_reg(st->spi, ADXRS290_REG_FILTER, val);
}
static int adxrs290_initial_setup(struct iio_dev *indio_dev)
{
struct adxrs290_state *st = iio_priv(indio_dev);
st->mode = ADXRS290_MODE_MEASUREMENT;
return adxrs290_spi_write_reg(st->spi,
ADXRS290_REG_POWER_CTL,
ADXRS290_MEASUREMENT | ADXRS290_TSM);
}
static int adxrs290_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct adxrs290_state *st = iio_priv(indio_dev);
unsigned int t;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_ANGL_VEL:
ret = adxrs290_get_rate_data(indio_dev,
ADXRS290_READ_REG(chan->address),
val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_TEMP:
ret = adxrs290_get_temp_data(indio_dev, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
/* 1 LSB = 0.005 degrees/sec */
*val = 0;
*val2 = 87266;
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
/* 1 LSB = 0.1 degrees Celsius */
*val = 100;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
switch (chan->type) {
case IIO_ANGL_VEL:
t = st->lpf_3db_freq_idx;
*val = adxrs290_lpf_3db_freq_hz_table[t][0];
*val2 = adxrs290_lpf_3db_freq_hz_table[t][1];
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
switch (chan->type) {
case IIO_ANGL_VEL:
t = st->hpf_3db_freq_idx;
*val = adxrs290_hpf_3db_freq_hz_table[t][0];
*val2 = adxrs290_hpf_3db_freq_hz_table[t][1];
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
return -EINVAL;
}
static int adxrs290_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct adxrs290_state *st = iio_priv(indio_dev);
int lpf_idx, hpf_idx;
switch (mask) {
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
lpf_idx = adxrs290_find_match(adxrs290_lpf_3db_freq_hz_table,
ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table),
val, val2);
if (lpf_idx < 0)
return -EINVAL;
/* caching the updated state of the low-pass filter */
st->lpf_3db_freq_idx = lpf_idx;
/* retrieving the current state of the high-pass filter */
hpf_idx = st->hpf_3db_freq_idx;
return adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx);
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
hpf_idx = adxrs290_find_match(adxrs290_hpf_3db_freq_hz_table,
ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table),
val, val2);
if (hpf_idx < 0)
return -EINVAL;
/* caching the updated state of the high-pass filter */
st->hpf_3db_freq_idx = hpf_idx;
/* retrieving the current state of the low-pass filter */
lpf_idx = st->lpf_3db_freq_idx;
return adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx);
}
return -EINVAL;
}
static int adxrs290_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*vals = (const int *)adxrs290_lpf_3db_freq_hz_table;
*type = IIO_VAL_INT_PLUS_MICRO;
/* Values are stored in a 2D matrix */
*length = ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table) * 2;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
*vals = (const int *)adxrs290_hpf_3db_freq_hz_table;
*type = IIO_VAL_INT_PLUS_MICRO;
/* Values are stored in a 2D matrix */
*length = ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table) * 2;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
#define ADXRS290_ANGL_VEL_CHANNEL(reg, axis) { \
.type = IIO_ANGL_VEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
}
static const struct iio_chan_spec adxrs290_channels[] = {
ADXRS290_ANGL_VEL_CHANNEL(ADXRS290_REG_DATAX0, X),
ADXRS290_ANGL_VEL_CHANNEL(ADXRS290_REG_DATAY0, Y),
{
.type = IIO_TEMP,
.address = ADXRS290_REG_TEMP0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static const struct iio_info adxrs290_info = {
.read_raw = &adxrs290_read_raw,
.write_raw = &adxrs290_write_raw,
.read_avail = &adxrs290_read_avail,
};
static int adxrs290_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adxrs290_state *st;
u8 val, val2;
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;
indio_dev->name = "adxrs290";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = adxrs290_channels;
indio_dev->num_channels = ARRAY_SIZE(adxrs290_channels);
indio_dev->info = &adxrs290_info;
mutex_init(&st->lock);
val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_ADI_ID));
if (val != ADXRS290_ADI_ID) {
dev_err(&spi->dev, "Wrong ADI ID 0x%02x\n", val);
return -ENODEV;
}
val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_MEMS_ID));
if (val != ADXRS290_MEMS_ID) {
dev_err(&spi->dev, "Wrong MEMS ID 0x%02x\n", val);
return -ENODEV;
}
val = spi_w8r8(spi, ADXRS290_READ_REG(ADXRS290_REG_DEV_ID));
if (val != ADXRS290_DEV_ID) {
dev_err(&spi->dev, "Wrong DEV ID 0x%02x\n", val);
return -ENODEV;
}
/* default mode the gyroscope starts in */
st->mode = ADXRS290_MODE_STANDBY;
/* switch to measurement mode and switch on the temperature sensor */
ret = adxrs290_initial_setup(indio_dev);
if (ret < 0)
return ret;
/* max transition time to measurement mode */
msleep(ADXRS290_MAX_TRANSITION_TIME_MS);
ret = adxrs290_get_3db_freq(indio_dev, &val, &val2);
if (ret < 0)
return ret;
st->lpf_3db_freq_idx = val;
st->hpf_3db_freq_idx = val2;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id adxrs290_of_match[] = {
{ .compatible = "adi,adxrs290" },
{ }
};
MODULE_DEVICE_TABLE(of, adxrs290_of_match);
static struct spi_driver adxrs290_driver = {
.driver = {
.name = "adxrs290",
.of_match_table = adxrs290_of_match,
},
.probe = adxrs290_probe,
};
module_spi_driver(adxrs290_driver);
MODULE_AUTHOR("Nishant Malpani <nish.malpani25@gmail.com>");
MODULE_DESCRIPTION("Analog Devices ADXRS290 Gyroscope SPI driver");
MODULE_LICENSE("GPL");
......@@ -2,7 +2,7 @@
/*
* max30102.c - Support for MAX30102 heart rate and pulse oximeter sensor
*
* Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
* Copyright (C) 2017 Matt Ranostay <matt.ranostay@konsulko.com>
*
* Support for MAX30105 optical particle sensor
* Copyright (C) 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
......@@ -632,6 +632,6 @@ static struct i2c_driver max30102_driver = {
};
module_i2c_driver(max30102_driver);
MODULE_AUTHOR("Matt Ranostay <matt@ranostay.consulting>");
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("MAX30102 heart rate/pulse oximeter and MAX30105 particle sensor driver");
MODULE_LICENSE("GPL");
......@@ -38,6 +38,16 @@ config HDC100X
To compile this driver as a module, choose M here: the module
will be called hdc100x.
config HDC2010
tristate "TI HDC2010 relative humidity and temperature sensor"
depends on I2C
help
Say yes here to build support for the Texas Instruments
HDC2010 and HDC2080 relative humidity and temperature sensors.
To compile this driver as a module, choose M here: the module
will be called hdc2010.
config HID_SENSOR_HUMIDITY
tristate "HID Environmental humidity sensor"
depends on HID_SENSOR_HUB
......
......@@ -6,6 +6,7 @@
obj-$(CONFIG_AM2315) += am2315.o
obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_HDC100X) += hdc100x.o
obj-$(CONFIG_HDC2010) += hdc2010.o
obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o
hts221-y := hts221_core.o \
......
// SPDX-License-Identifier: GPL-2.0+
/*
* hdc2010.c - Support for the TI HDC2010 and HDC2080
* temperature + relative humidity sensors
*
* Copyright (C) 2020 Norphonic AS
* Author: Eugene Zaikonnikov <ez@norphonic.com>
*
* Datasheet: https://www.ti.com/product/HDC2010/datasheet
* Datasheet: https://www.ti.com/product/HDC2080/datasheet
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define HDC2010_REG_TEMP_LOW 0x00
#define HDC2010_REG_TEMP_HIGH 0x01
#define HDC2010_REG_HUMIDITY_LOW 0x02
#define HDC2010_REG_HUMIDITY_HIGH 0x03
#define HDC2010_REG_INTERRUPT_DRDY 0x04
#define HDC2010_REG_TEMP_MAX 0x05
#define HDC2010_REG_HUMIDITY_MAX 0x06
#define HDC2010_REG_INTERRUPT_EN 0x07
#define HDC2010_REG_TEMP_OFFSET_ADJ 0x08
#define HDC2010_REG_HUMIDITY_OFFSET_ADJ 0x09
#define HDC2010_REG_TEMP_THR_L 0x0a
#define HDC2010_REG_TEMP_THR_H 0x0b
#define HDC2010_REG_RH_THR_L 0x0c
#define HDC2010_REG_RH_THR_H 0x0d
#define HDC2010_REG_RESET_DRDY_INT_CONF 0x0e
#define HDC2010_REG_MEASUREMENT_CONF 0x0f
#define HDC2010_MEAS_CONF GENMASK(2, 1)
#define HDC2010_MEAS_TRIG BIT(0)
#define HDC2010_HEATER_EN BIT(3)
#define HDC2010_AMM GENMASK(6, 4)
struct hdc2010_data {
struct i2c_client *client;
struct mutex lock;
u8 measurement_config;
u8 interrupt_config;
u8 drdy_config;
};
enum hdc2010_addr_groups {
HDC2010_GROUP_TEMP = 0,
HDC2010_GROUP_HUMIDITY,
};
struct hdc2010_reg_record {
unsigned long primary;
unsigned long peak;
};
static const struct hdc2010_reg_record hdc2010_reg_translation[] = {
[HDC2010_GROUP_TEMP] = {
.primary = HDC2010_REG_TEMP_LOW,
.peak = HDC2010_REG_TEMP_MAX,
},
[HDC2010_GROUP_HUMIDITY] = {
.primary = HDC2010_REG_HUMIDITY_LOW,
.peak = HDC2010_REG_HUMIDITY_MAX,
},
};
static IIO_CONST_ATTR(out_current_heater_raw_available, "0 1");
static struct attribute *hdc2010_attributes[] = {
&iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
NULL
};
static const struct attribute_group hdc2010_attribute_group = {
.attrs = hdc2010_attributes,
};
static const struct iio_chan_spec hdc2010_channels[] = {
{
.type = IIO_TEMP,
.address = HDC2010_GROUP_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PEAK) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
{
.type = IIO_HUMIDITYRELATIVE,
.address = HDC2010_GROUP_HUMIDITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_PEAK) |
BIT(IIO_CHAN_INFO_SCALE),
},
{
.type = IIO_CURRENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.extend_name = "heater",
.output = 1,
},
};
static int hdc2010_update_drdy_config(struct hdc2010_data *data,
char mask, char val)
{
u8 tmp = (~mask & data->drdy_config) | val;
int ret;
ret = i2c_smbus_write_byte_data(data->client,
HDC2010_REG_RESET_DRDY_INT_CONF, tmp);
if (ret)
return ret;
data->drdy_config = tmp;
return 0;
}
static int hdc2010_get_prim_measurement_word(struct hdc2010_data *data,
struct iio_chan_spec const *chan)
{
struct i2c_client *client = data->client;
s32 ret;
ret = i2c_smbus_read_word_data(client,
hdc2010_reg_translation[chan->address].primary);
if (ret < 0)
dev_err(&client->dev, "Could not read sensor measurement word\n");
return ret;
}
static int hdc2010_get_peak_measurement_byte(struct hdc2010_data *data,
struct iio_chan_spec const *chan)
{
struct i2c_client *client = data->client;
s32 ret;
ret = i2c_smbus_read_byte_data(client,
hdc2010_reg_translation[chan->address].peak);
if (ret < 0)
dev_err(&client->dev, "Could not read sensor measurement byte\n");
return ret;
}
static int hdc2010_get_heater_status(struct hdc2010_data *data)
{
return !!(data->drdy_config & HDC2010_HEATER_EN);
}
static int hdc2010_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct hdc2010_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW: {
int ret;
if (chan->type == IIO_CURRENT) {
*val = hdc2010_get_heater_status(data);
return IIO_VAL_INT;
}
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&data->lock);
ret = hdc2010_get_prim_measurement_word(data, chan);
mutex_unlock(&data->lock);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_PEAK: {
int ret;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&data->lock);
ret = hdc2010_get_peak_measurement_byte(data, chan);
mutex_unlock(&data->lock);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
/* Scaling up the value so we can use same offset as RAW */
*val = ret * 256;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_SCALE:
*val2 = 65536;
if (chan->type == IIO_TEMP)
*val = 165000;
else
*val = 100000;
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_OFFSET:
*val = -15887;
*val2 = 515151;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int hdc2010_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct hdc2010_data *data = iio_priv(indio_dev);
int new, ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_CURRENT || val2 != 0)
return -EINVAL;
switch (val) {
case 1:
new = HDC2010_HEATER_EN;
break;
case 0:
new = 0;
break;
default:
return -EINVAL;
}
mutex_lock(&data->lock);
ret = hdc2010_update_drdy_config(data, HDC2010_HEATER_EN, new);
mutex_unlock(&data->lock);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_info hdc2010_info = {
.read_raw = hdc2010_read_raw,
.write_raw = hdc2010_write_raw,
.attrs = &hdc2010_attribute_group,
};
static int hdc2010_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct hdc2010_data *data;
u8 tmp;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
return -EOPNOTSUPP;
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;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
/*
* As DEVICE ID register does not differentiate between
* HDC2010 and HDC2080, we have the name hardcoded
*/
indio_dev->name = "hdc2010";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &hdc2010_info;
indio_dev->channels = hdc2010_channels;
indio_dev->num_channels = ARRAY_SIZE(hdc2010_channels);
/* Enable Automatic Measurement Mode at 5Hz */
ret = hdc2010_update_drdy_config(data, HDC2010_AMM, HDC2010_AMM);
if (ret)
return ret;
/*
* We enable both temp and humidity measurement.
* However the measurement won't start even in AMM until triggered.
*/
tmp = (data->measurement_config & ~HDC2010_MEAS_CONF) |
HDC2010_MEAS_TRIG;
ret = i2c_smbus_write_byte_data(client, HDC2010_REG_MEASUREMENT_CONF, tmp);
if (ret) {
dev_warn(&client->dev, "Unable to set up measurement\n");
if (hdc2010_update_drdy_config(data, HDC2010_AMM, 0))
dev_warn(&client->dev, "Unable to restore default AMM\n");
return ret;
}
data->measurement_config = tmp;
return iio_device_register(indio_dev);
}
static int hdc2010_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct hdc2010_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
/* Disable Automatic Measurement Mode */
if (hdc2010_update_drdy_config(data, HDC2010_AMM, 0))
dev_warn(&client->dev, "Unable to restore default AMM\n");
return 0;
}
static const struct i2c_device_id hdc2010_id[] = {
{ "hdc2010" },
{ "hdc2080" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc2010_id);
static const struct of_device_id hdc2010_dt_ids[] = {
{ .compatible = "ti,hdc2010" },
{ .compatible = "ti,hdc2080" },
{ }
};
MODULE_DEVICE_TABLE(of, hdc2010_dt_ids);
static struct i2c_driver hdc2010_driver = {
.driver = {
.name = "hdc2010",
.of_match_table = hdc2010_dt_ids,
},
.probe = hdc2010_probe,
.remove = hdc2010_remove,
.id_table = hdc2010_id,
};
module_i2c_driver(hdc2010_driver);
MODULE_AUTHOR("Eugene Zaikonnikov <ez@norphonic.com>");
MODULE_DESCRIPTION("TI HDC2010 humidity and temperature sensor driver");
MODULE_LICENSE("GPL");
......@@ -30,7 +30,7 @@ int iio_trigger_detach_poll_func(struct iio_trigger *trig,
* iio_device_register_trigger_consumer() - set up an iio_dev to use triggers
* @indio_dev: iio_dev associated with the device that will consume the trigger
**/
static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
static inline int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
return 0;
}
......@@ -39,7 +39,7 @@ static int iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
* iio_device_unregister_trigger_consumer() - reverse the registration process
* @indio_dev: iio_dev associated with the device that consumed the trigger
**/
static void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
static inline void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
{
}
......
......@@ -1475,22 +1475,14 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
}
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);
}
if (IS_ERR(st->vdd_supply))
return dev_err_probe(dev, PTR_ERR(st->vdd_supply),
"Failed to get vdd regulator\n");
st->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(st->vddio_supply)) {
if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vddio regulator %d\n",
(int)PTR_ERR(st->vddio_supply));
return PTR_ERR(st->vddio_supply);
}
if (IS_ERR(st->vddio_supply))
return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
"Failed to get vddio regulator\n");
result = regulator_enable(st->vdd_supply);
if (result) {
......
......@@ -133,6 +133,7 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_PM10] = "pm10",
[IIO_MOD_ETHANOL] = "ethanol",
[IIO_MOD_H2] = "h2",
[IIO_MOD_O2] = "o2",
};
/* relies on pairs of these shared then separate */
......
......@@ -86,6 +86,21 @@ config APDS9960
To compile this driver as a module, choose M here: the
module will be called apds9960
config AS73211
tristate "AMS AS73211 XYZ color sensor"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for the AMS AS73211
JENCOLOR(R) Digital XYZ Sensor.
For triggered measurements, you will need an additional trigger driver
like IIO_HRTIMER_TRIGGER or IIO_SYSFS_TRIGGER.
This driver can also be built as a module. If so, the module
will be called as73211.
config BH1750
tristate "ROHM BH1750 ambient light sensor"
depends on I2C
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_AL3010) += al3010.o
obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_AS73211) += as73211.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_BH1780) += bh1780.o
obj-$(CONFIG_CM32181) += cm32181.o
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
*
* Author: Christian Eggers <ceggers@arri.de>
*
* Copyright (c) 2020 ARRI Lighting
*
* Color light sensor with 16-bit channels for x, y, z and temperature);
* 7-bit I2C slave address 0x74 .. 0x77.
*
* Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
*/
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#define HZ_PER_KHZ 1000
#define AS73211_DRV_NAME "as73211"
/* AS73211 configuration registers */
#define AS73211_REG_OSR 0x0
#define AS73211_REG_AGEN 0x2
#define AS73211_REG_CREG1 0x6
#define AS73211_REG_CREG2 0x7
#define AS73211_REG_CREG3 0x8
/* AS73211 output register bank */
#define AS73211_OUT_OSR_STATUS 0
#define AS73211_OUT_TEMP 1
#define AS73211_OUT_MRES1 2
#define AS73211_OUT_MRES2 3
#define AS73211_OUT_MRES3 4
#define AS73211_OSR_SS BIT(7)
#define AS73211_OSR_PD BIT(6)
#define AS73211_OSR_SW_RES BIT(3)
#define AS73211_OSR_DOS_MASK GENMASK(2, 0)
#define AS73211_OSR_DOS_CONFIG FIELD_PREP(AS73211_OSR_DOS_MASK, 0x2)
#define AS73211_OSR_DOS_MEASURE FIELD_PREP(AS73211_OSR_DOS_MASK, 0x3)
#define AS73211_AGEN_DEVID_MASK GENMASK(7, 4)
#define AS73211_AGEN_DEVID(x) FIELD_PREP(AS73211_AGEN_DEVID_MASK, (x))
#define AS73211_AGEN_MUT_MASK GENMASK(3, 0)
#define AS73211_AGEN_MUT(x) FIELD_PREP(AS73211_AGEN_MUT_MASK, (x))
#define AS73211_CREG1_GAIN_MASK GENMASK(7, 4)
#define AS73211_CREG1_GAIN_1 11
#define AS73211_CREG1_TIME_MASK GENMASK(3, 0)
#define AS73211_CREG3_CCLK_MASK GENMASK(1, 0)
#define AS73211_OSR_STATUS_OUTCONVOF BIT(15)
#define AS73211_OSR_STATUS_MRESOF BIT(14)
#define AS73211_OSR_STATUS_ADCOF BIT(13)
#define AS73211_OSR_STATUS_LDATA BIT(12)
#define AS73211_OSR_STATUS_NDATA BIT(11)
#define AS73211_OSR_STATUS_NOTREADY BIT(10)
#define AS73211_SAMPLE_FREQ_BASE 1024000
#define AS73211_SAMPLE_TIME_NUM 15
#define AS73211_SAMPLE_TIME_MAX_MS BIT(AS73211_SAMPLE_TIME_NUM - 1)
/* Available sample frequencies are 1.024MHz multiplied by powers of two. */
static const int as73211_samp_freq_avail[] = {
AS73211_SAMPLE_FREQ_BASE * 1,
AS73211_SAMPLE_FREQ_BASE * 2,
AS73211_SAMPLE_FREQ_BASE * 4,
AS73211_SAMPLE_FREQ_BASE * 8,
};
static const int as73211_hardwaregain_avail[] = {
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
};
/**
* struct as73211_data - Instance data for one AS73211
* @client: I2C client.
* @osr: Cached Operational State Register.
* @creg1: Cached Configuration Register 1.
* @creg2: Cached Configuration Register 2.
* @creg3: Cached Configuration Register 3.
* @mutex: Keeps cached registers in sync with the device.
* @completion: Completion to wait for interrupt.
* @int_time_avail: Available integration times (depend on sampling frequency).
*/
struct as73211_data {
struct i2c_client *client;
u8 osr;
u8 creg1;
u8 creg2;
u8 creg3;
struct mutex mutex;
struct completion completion;
int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2];
};
#define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \
.type = IIO_INTENSITY, \
.modified = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_type = \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
.channel2 = IIO_MOD_##_color, \
.address = _addr, \
.scan_index = _si, \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
#define AS73211_OFFSET_TEMP_INT (-66)
#define AS73211_OFFSET_TEMP_MICRO 900000
#define AS73211_SCALE_TEMP_INT 0
#define AS73211_SCALE_TEMP_MICRO 50000
#define AS73211_SCALE_X 277071108 /* nW/m^2 */
#define AS73211_SCALE_Y 298384270 /* nW/m^2 */
#define AS73211_SCALE_Z 160241927 /* nW/m^2 */
/* Channel order MUST match devices result register order */
#define AS73211_SCAN_INDEX_TEMP 0
#define AS73211_SCAN_INDEX_X 1
#define AS73211_SCAN_INDEX_Y 2
#define AS73211_SCAN_INDEX_Z 3
#define AS73211_SCAN_INDEX_TS 4
#define AS73211_SCAN_MASK_COLOR ( \
BIT(AS73211_SCAN_INDEX_X) | \
BIT(AS73211_SCAN_INDEX_Y) | \
BIT(AS73211_SCAN_INDEX_Z))
#define AS73211_SCAN_MASK_ALL ( \
BIT(AS73211_SCAN_INDEX_TEMP) | \
AS73211_SCAN_MASK_COLOR)
static const struct iio_chan_spec as73211_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
.address = AS73211_OUT_TEMP,
.scan_index = AS73211_SCAN_INDEX_TEMP,
.scan_type = {
.sign = 'u',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
}
},
AS73211_COLOR_CHANNEL(X, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1),
AS73211_COLOR_CHANNEL(Y, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2),
AS73211_COLOR_CHANNEL(Z, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3),
IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
};
static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data)
{
/*
* Return integration time in units of 1024 clock cycles. Integration time
* in CREG1 is in powers of 2 (x 1024 cycles).
*/
return BIT(FIELD_GET(AS73211_CREG1_TIME_MASK, data->creg1));
}
static unsigned int as73211_integration_time_us(struct as73211_data *data,
unsigned int integration_time_1024cyc)
{
/*
* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz)
* t_cycl is configured in CREG1 in powers of 2 (x 1024 cycles)
* t_int_us = 1 / (f_samp) * t_cycl * US_PER_SEC
* = 1 / (2^CREG3_CCLK * 1,024,000) * 2^CREG1_CYCLES * 1,024 * US_PER_SEC
* = 2^(-CREG3_CCLK) * 2^CREG1_CYCLES * 1,000
* In order to get rid of negative exponents, we extend the "fraction"
* by 2^3 (CREG3_CCLK,max = 3)
* t_int_us = 2^(3-CREG3_CCLK) * 2^CREG1_CYCLES * 125
*/
return BIT(3 - FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) *
integration_time_1024cyc * 125;
}
static void as73211_integration_time_calc_avail(struct as73211_data *data)
{
int i;
for (i = 0; i < ARRAY_SIZE(data->int_time_avail) / 2; i++) {
unsigned int time_us = as73211_integration_time_us(data, BIT(i));
data->int_time_avail[i * 2 + 0] = time_us / USEC_PER_SEC;
data->int_time_avail[i * 2 + 1] = time_us % USEC_PER_SEC;
}
}
static unsigned int as73211_gain(struct as73211_data *data)
{
/* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */
return BIT(AS73211_CREG1_GAIN_1 - FIELD_GET(AS73211_CREG1_GAIN_MASK, data->creg1));
}
/* must be called with as73211_data::mutex held. */
static int as73211_req_data(struct as73211_data *data)
{
unsigned int time_us = as73211_integration_time_us(data,
as73211_integration_time_1024cyc(data));
struct device *dev = &data->client->dev;
union i2c_smbus_data smbus_data;
u16 osr_status;
int ret;
if (data->client->irq)
reinit_completion(&data->completion);
/*
* During measurement, there should be no traffic on the i2c bus as the
* electrical noise would disturb the measurement process.
*/
i2c_lock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
data->osr &= ~AS73211_OSR_DOS_MASK;
data->osr |= AS73211_OSR_DOS_MEASURE | AS73211_OSR_SS;
smbus_data.byte = data->osr;
ret = __i2c_smbus_xfer(data->client->adapter, data->client->addr,
data->client->flags, I2C_SMBUS_WRITE,
AS73211_REG_OSR, I2C_SMBUS_BYTE_DATA, &smbus_data);
if (ret < 0) {
i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
return ret;
}
/*
* Reset AS73211_OSR_SS (is self clearing) in order to avoid unintentional
* triggering of further measurements later.
*/
data->osr &= ~AS73211_OSR_SS;
/*
* Add some extra margin for the timeout. sensor timing is not as precise
* as our one ...
*/
time_us += time_us / 8;
if (data->client->irq) {
ret = wait_for_completion_timeout(&data->completion, usecs_to_jiffies(time_us));
if (!ret) {
dev_err(dev, "timeout waiting for READY IRQ\n");
i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
return -ETIMEDOUT;
}
} else {
/* Wait integration time */
usleep_range(time_us, 2 * time_us);
}
i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
ret = i2c_smbus_read_word_data(data->client, AS73211_OUT_OSR_STATUS);
if (ret < 0)
return ret;
osr_status = ret;
if (osr_status != (AS73211_OSR_DOS_MEASURE | AS73211_OSR_STATUS_NDATA)) {
if (osr_status & AS73211_OSR_SS) {
dev_err(dev, "%s() Measurement has not stopped\n", __func__);
return -ETIME;
}
if (osr_status & AS73211_OSR_STATUS_NOTREADY) {
dev_err(dev, "%s() Data is not ready\n", __func__);
return -ENODATA;
}
if (!(osr_status & AS73211_OSR_STATUS_NDATA)) {
dev_err(dev, "%s() No new data available\n", __func__);
return -ENODATA;
}
if (osr_status & AS73211_OSR_STATUS_LDATA) {
dev_err(dev, "%s() Result buffer overrun\n", __func__);
return -ENOBUFS;
}
if (osr_status & AS73211_OSR_STATUS_ADCOF) {
dev_err(dev, "%s() ADC overflow\n", __func__);
return -EOVERFLOW;
}
if (osr_status & AS73211_OSR_STATUS_MRESOF) {
dev_err(dev, "%s() Measurement result overflow\n", __func__);
return -EOVERFLOW;
}
if (osr_status & AS73211_OSR_STATUS_OUTCONVOF) {
dev_err(dev, "%s() Timer overflow\n", __func__);
return -EOVERFLOW;
}
dev_err(dev, "%s() Unexpected status value\n", __func__);
return -EIO;
}
return 0;
}
static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct as73211_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW: {
int ret;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret < 0)
return ret;
ret = as73211_req_data(data);
if (ret < 0) {
iio_device_release_direct_mode(indio_dev);
return ret;
}
ret = i2c_smbus_read_word_data(data->client, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_OFFSET:
*val = AS73211_OFFSET_TEMP_INT;
*val2 = AS73211_OFFSET_TEMP_MICRO;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_TEMP:
*val = AS73211_SCALE_TEMP_INT;
*val2 = AS73211_SCALE_TEMP_MICRO;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_INTENSITY: {
unsigned int scale;
switch (chan->channel2) {
case IIO_MOD_X:
scale = AS73211_SCALE_X;
break;
case IIO_MOD_Y:
scale = AS73211_SCALE_Y;
break;
case IIO_MOD_Z:
scale = AS73211_SCALE_Z;
break;
default:
return -EINVAL;
}
scale /= as73211_gain(data);
scale /= as73211_integration_time_1024cyc(data);
*val = scale;
return IIO_VAL_INT;
default:
return -EINVAL;
}}
case IIO_CHAN_INFO_SAMP_FREQ:
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
*val = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) *
AS73211_SAMPLE_FREQ_BASE;
return IIO_VAL_INT;
case IIO_CHAN_INFO_HARDWAREGAIN:
*val = as73211_gain(data);
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME: {
unsigned int time_us;
mutex_lock(&data->mutex);
time_us = as73211_integration_time_us(data, as73211_integration_time_1024cyc(data));
mutex_unlock(&data->mutex);
*val = time_us / USEC_PER_SEC;
*val2 = time_us % USEC_PER_SEC;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}}
}
static int as73211_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
const int **vals, int *type, int *length, long mask)
{
struct as73211_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*length = ARRAY_SIZE(as73211_samp_freq_avail);
*vals = as73211_samp_freq_avail;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_HARDWAREGAIN:
*length = ARRAY_SIZE(as73211_hardwaregain_avail);
*vals = as73211_hardwaregain_avail;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_INT_TIME:
*length = ARRAY_SIZE(data->int_time_avail);
*vals = data->int_time_avail;
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int _as73211_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan __always_unused,
int val, int val2, long mask)
{
struct as73211_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ: {
int reg_bits, freq_kHz = val / HZ_PER_KHZ; /* 1024, 2048, ... */
/* val must be 1024 * 2^x */
if (val < 0 || (freq_kHz * HZ_PER_KHZ) != val ||
!is_power_of_2(freq_kHz) || val2)
return -EINVAL;
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz (=2^10)) */
reg_bits = ilog2(freq_kHz) - 10;
if (!FIELD_FIT(AS73211_CREG3_CCLK_MASK, reg_bits))
return -EINVAL;
data->creg3 &= ~AS73211_CREG3_CCLK_MASK;
data->creg3 |= FIELD_PREP(AS73211_CREG3_CCLK_MASK, reg_bits);
as73211_integration_time_calc_avail(data);
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG3, data->creg3);
if (ret < 0)
return ret;
return 0;
}
case IIO_CHAN_INFO_HARDWAREGAIN: {
unsigned int reg_bits;
if (val < 0 || !is_power_of_2(val) || val2)
return -EINVAL;
/* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */
reg_bits = AS73211_CREG1_GAIN_1 - ilog2(val);
if (!FIELD_FIT(AS73211_CREG1_GAIN_MASK, reg_bits))
return -EINVAL;
data->creg1 &= ~AS73211_CREG1_GAIN_MASK;
data->creg1 |= FIELD_PREP(AS73211_CREG1_GAIN_MASK, reg_bits);
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG1, data->creg1);
if (ret < 0)
return ret;
return 0;
}
case IIO_CHAN_INFO_INT_TIME: {
int val_us = val * USEC_PER_SEC + val2;
int time_ms;
int reg_bits;
/* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
int f_samp_1_024mhz = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3));
/*
* time_ms = time_us * US_PER_MS * f_samp_1_024mhz / MHZ_PER_HZ
* = time_us * f_samp_1_024mhz / 1000
*/
time_ms = (val_us * f_samp_1_024mhz) / 1000; /* 1 ms, 2 ms, ... (power of two) */
if (time_ms < 0 || !is_power_of_2(time_ms) || time_ms > AS73211_SAMPLE_TIME_MAX_MS)
return -EINVAL;
reg_bits = ilog2(time_ms);
if (!FIELD_FIT(AS73211_CREG1_TIME_MASK, reg_bits))
return -EINVAL; /* not possible due to previous tests */
data->creg1 &= ~AS73211_CREG1_TIME_MASK;
data->creg1 |= FIELD_PREP(AS73211_CREG1_TIME_MASK, reg_bits);
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG1, data->creg1);
if (ret < 0)
return ret;
return 0;
default:
return -EINVAL;
}}
}
static int as73211_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct as73211_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret < 0)
goto error_unlock;
/* Need to switch to config mode ... */
if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) {
data->osr &= ~AS73211_OSR_DOS_MASK;
data->osr |= AS73211_OSR_DOS_CONFIG;
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
if (ret < 0)
goto error_release;
}
ret = _as73211_write_raw(indio_dev, chan, val, val2, mask);
error_release:
iio_device_release_direct_mode(indio_dev);
error_unlock:
mutex_unlock(&data->mutex);
return ret;
}
static irqreturn_t as73211_ready_handler(int irq __always_unused, void *priv)
{
struct as73211_data *data = iio_priv(priv);
complete(&data->completion);
return IRQ_HANDLED;
}
static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct as73211_data *data = iio_priv(indio_dev);
struct {
__le16 chan[4];
s64 ts __aligned(8);
} scan;
int data_result, ret;
mutex_lock(&data->mutex);
data_result = as73211_req_data(data);
if (data_result < 0 && data_result != -EOVERFLOW)
goto done; /* don't push any data for errors other than EOVERFLOW */
if (*indio_dev->active_scan_mask == AS73211_SCAN_MASK_ALL) {
/* Optimization for reading all (color + temperature) channels */
u8 addr = as73211_channels[0].address;
struct i2c_msg msgs[] = {
{
.addr = data->client->addr,
.flags = 0,
.len = 1,
.buf = &addr,
},
{
.addr = data->client->addr,
.flags = I2C_M_RD,
.len = sizeof(scan.chan),
.buf = (u8 *)&scan.chan,
},
};
ret = i2c_transfer(data->client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
goto done;
} else {
/* Optimization for reading only color channels */
/* AS73211 starts reading at address 2 */
ret = i2c_master_recv(data->client,
(char *)&scan.chan[1], 3 * sizeof(scan.chan[1]));
if (ret < 0)
goto done;
}
if (data_result) {
/*
* Saturate all channels (in case of overflows). Temperature channel
* is not affected by overflows.
*/
scan.chan[1] = cpu_to_le16(U16_MAX);
scan.chan[2] = cpu_to_le16(U16_MAX);
scan.chan[3] = cpu_to_le16(U16_MAX);
}
iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
done:
mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct iio_info as73211_info = {
.read_raw = as73211_read_raw,
.read_avail = as73211_read_avail,
.write_raw = as73211_write_raw,
};
static int as73211_power(struct iio_dev *indio_dev, bool state)
{
struct as73211_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
if (state)
data->osr &= ~AS73211_OSR_PD;
else
data->osr |= AS73211_OSR_PD;
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
mutex_unlock(&data->mutex);
if (ret < 0)
return ret;
return 0;
}
static void as73211_power_disable(void *data)
{
struct iio_dev *indio_dev = data;
as73211_power(indio_dev, false);
}
static int as73211_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct as73211_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->mutex);
init_completion(&data->completion);
indio_dev->info = &as73211_info;
indio_dev->name = AS73211_DRV_NAME;
indio_dev->channels = as73211_channels;
indio_dev->num_channels = ARRAY_SIZE(as73211_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
if (ret < 0)
return ret;
data->osr = ret;
/* reset device */
data->osr |= AS73211_OSR_SW_RES;
ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
if (ret < 0)
return ret;
data->osr = ret;
/*
* Reading AGEN is only possible after reset (AGEN is not available if
* device is in measurement mode).
*/
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_AGEN);
if (ret < 0)
return ret;
/* At the time of writing this driver, only DEVID 2 and MUT 1 are known. */
if ((ret & AS73211_AGEN_DEVID_MASK) != AS73211_AGEN_DEVID(2) ||
(ret & AS73211_AGEN_MUT_MASK) != AS73211_AGEN_MUT(1))
return -ENODEV;
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG1);
if (ret < 0)
return ret;
data->creg1 = ret;
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG2);
if (ret < 0)
return ret;
data->creg2 = ret;
ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG3);
if (ret < 0)
return ret;
data->creg3 = ret;
as73211_integration_time_calc_avail(data);
ret = as73211_power(indio_dev, true);
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(dev, as73211_power_disable, indio_dev);
if (ret)
return ret;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, as73211_trigger_handler, NULL);
if (ret)
return ret;
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL,
as73211_ready_handler,
IRQF_ONESHOT,
client->name, indio_dev);
if (ret)
return ret;
}
return devm_iio_device_register(dev, indio_dev);
}
static int __maybe_unused as73211_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
return as73211_power(indio_dev, false);
}
static int __maybe_unused as73211_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
return as73211_power(indio_dev, true);
}
static SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend, as73211_resume);
static const struct of_device_id as73211_of_match[] = {
{ .compatible = "ams,as73211" },
{ }
};
MODULE_DEVICE_TABLE(of, as73211_of_match);
static const struct i2c_device_id as73211_id[] = {
{ "as73211", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, as73211_id);
static struct i2c_driver as73211_driver = {
.driver = {
.name = AS73211_DRV_NAME,
.of_match_table = as73211_of_match,
.pm = &as73211_pm_ops,
},
.probe_new = as73211_probe,
.id_table = as73211_id,
};
module_i2c_driver(as73211_driver);
MODULE_AUTHOR("Christian Eggers <ceggers@arri.de>");
MODULE_DESCRIPTION("AS73211 XYZ True Color Sensor driver");
MODULE_LICENSE("GPL");
......@@ -746,12 +746,9 @@ static int isl29018_probe(struct i2c_client *client,
chip->suspended = false;
chip->vcc_reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(chip->vcc_reg)) {
err = PTR_ERR(chip->vcc_reg);
if (err != -EPROBE_DEFER)
dev_err(&client->dev, "failed to get VCC regulator!\n");
return err;
}
if (IS_ERR(chip->vcc_reg))
return dev_err_probe(&client->dev, PTR_ERR(chip->vcc_reg),
"failed to get VCC regulator!\n");
err = regulator_enable(chip->vcc_reg);
if (err) {
......
......@@ -1776,14 +1776,8 @@ static int tsl2772_probe(struct i2c_client *clientp,
ret = devm_regulator_bulk_get(&clientp->dev,
ARRAY_SIZE(chip->supplies),
chip->supplies);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(&clientp->dev,
"Failed to get regulators: %d\n",
ret);
return ret;
}
if (ret < 0)
return dev_err_probe(&clientp->dev, ret, "Failed to get regulators\n");
ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies);
if (ret < 0) {
......
......@@ -843,15 +843,8 @@ static int ak8974_probe(struct i2c_client *i2c,
ret = devm_regulator_bulk_get(&i2c->dev,
ARRAY_SIZE(ak8974->regs),
ak8974->regs);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(&i2c->dev, "cannot get regulators: %d\n", ret);
else
dev_dbg(&i2c->dev,
"regulators unavailable, deferring probe\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&i2c->dev, ret, "cannot get regulators\n");
ret = regulator_bulk_enable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
if (ret < 0) {
......
......@@ -476,22 +476,14 @@ static int mag3110_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(data->vdd_reg)) {
if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "failed to get VDD regulator!\n");
return PTR_ERR(data->vdd_reg);
}
if (IS_ERR(data->vdd_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg),
"failed to get VDD regulator!\n");
data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
if (IS_ERR(data->vddio_reg)) {
if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "failed to get VDDIO regulator!\n");
return PTR_ERR(data->vddio_reg);
}
if (IS_ERR(data->vddio_reg))
return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg),
"failed to get VDDIO regulator!\n");
ret = regulator_enable(data->vdd_reg);
if (ret) {
......
......@@ -354,11 +354,9 @@ static int mux_probe(struct platform_device *pdev)
return -ENODEV;
parent = devm_iio_channel_get(dev, "parent");
if (IS_ERR(parent)) {
if (PTR_ERR(parent) != -EPROBE_DEFER)
dev_err(dev, "failed to get parent channel\n");
return PTR_ERR(parent);
}
if (IS_ERR(parent))
return dev_err_probe(dev, PTR_ERR(parent),
"failed to get parent channel\n");
sizeof_ext_info = iio_get_channel_ext_info_count(parent);
if (sizeof_ext_info) {
......
......@@ -6,19 +6,21 @@
* Based on SX9500 driver and Semtech driver using the input framework
* <https://my.syncplicity.com/share/teouwsim8niiaud/
* linux-driver-SX9310_NoSmartHSensing>.
* Reworked April 2019 by Evan Green <evgreen@chromium.org>
* and January 2020 by Daniel Campello <campello@chromium.org>
* Reworked in April 2019 by Evan Green <evgreen@chromium.org>
* and in January 2020 by Daniel Campello <campello@chromium.org>.
*/
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/iio/buffer.h>
......@@ -33,45 +35,44 @@
#define SX9310_REG_IRQ_SRC 0x00
#define SX9310_REG_STAT0 0x01
#define SX9310_REG_STAT1 0x02
#define SX9310_REG_STAT1_COMPSTAT_MASK GENMASK(3, 0)
#define SX9310_REG_IRQ_MSK 0x03
#define SX9310_CONVDONE_IRQ BIT(3)
#define SX9310_FAR_IRQ BIT(5)
#define SX9310_CLOSE_IRQ BIT(6)
#define SX9310_EVENT_IRQ (SX9310_FAR_IRQ | \
SX9310_CLOSE_IRQ)
#define SX9310_REG_IRQ_FUNC 0x04
#define SX9310_REG_PROX_CTRL0 0x10
#define SX9310_REG_PROX_CTRL0_PROXSTAT2 0x10
#define SX9310_REG_PROX_CTRL0_EN_MASK 0x0F
#define SX9310_REG_PROX_CTRL0_SENSOREN_MASK GENMASK(3, 0)
#define SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK GENMASK(7, 4)
#define SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS 0x01
#define SX9310_REG_PROX_CTRL1 0x11
#define SX9310_REG_PROX_CTRL2 0x12
#define SX9310_REG_PROX_CTRL2_COMBMODE_ALL 0x80
#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC 0x04
#define SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 (0x02 << 6)
#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC (0x01 << 2)
#define SX9310_REG_PROX_CTRL3 0x13
#define SX9310_REG_PROX_CTRL3_GAIN0_X8 0x0c
#define SX9310_REG_PROX_CTRL3_GAIN0_X8 (0x03 << 2)
#define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02
#define SX9310_REG_PROX_CTRL4 0x14
#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07
#define SX9310_REG_PROX_CTRL5 0x15
#define SX9310_REG_PROX_CTRL5_RANGE_SMALL 0xc0
#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 0x04
#define SX9310_REG_PROX_CTRL5_RANGE_SMALL (0x03 << 6)
#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 (0x01 << 2)
#define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02
#define SX9310_REG_PROX_CTRL6 0x16
#define SX9310_REG_PROX_CTRL6_COMP_COMMON 0x20
#define SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT 0x20
#define SX9310_REG_PROX_CTRL7 0x17
#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 0x08
#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3)
#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05
#define SX9310_REG_PROX_CTRL8 0x18
#define SX9310_REG_PROX_CTRL9 0x19
#define SX9310_REG_PROX_CTRL8_9_PTHRESH12_28 0x40
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 0x88
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3)
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3)
#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 0x03
#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 0x05
#define SX9310_REG_PROX_CTRL10 0x1a
#define SX9310_REG_PROX_CTRL10_HYST_6PCT 0x10
#define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_8 0x12
#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_8 0x03
#define SX9310_REG_PROX_CTRL10_HYST_6PCT (0x01 << 4)
#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 0x01
#define SX9310_REG_PROX_CTRL11 0x1b
#define SX9310_REG_PROX_CTRL12 0x1c
#define SX9310_REG_PROX_CTRL13 0x1d
......@@ -82,8 +83,8 @@
#define SX9310_REG_PROX_CTRL18 0x22
#define SX9310_REG_PROX_CTRL19 0x23
#define SX9310_REG_SAR_CTRL0 0x2a
#define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES 0x40
#define SX9310_REG_SAR_CTRL0_SARHYST_8 0x10
#define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES (0x02 << 5)
#define SX9310_REG_SAR_CTRL0_SARHYST_8 (0x02 << 3)
#define SX9310_REG_SAR_CTRL1 0x2b
/* Each increment of the slope register is 0.0078125. */
#define SX9310_REG_SAR_CTRL1_SLOPE(_hnslope) (_hnslope / 78125)
......@@ -91,39 +92,28 @@
#define SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT 0x3c
#define SX9310_REG_SENSOR_SEL 0x30
#define SX9310_REG_USE_MSB 0x31
#define SX9310_REG_USE_LSB 0x32
#define SX9310_REG_AVG_MSB 0x33
#define SX9310_REG_AVG_LSB 0x34
#define SX9310_REG_DIFF_MSB 0x35
#define SX9310_REG_DIFF_LSB 0x36
#define SX9310_REG_OFFSET_MSB 0x37
#define SX9310_REG_OFFSET_LSB 0x38
#define SX9310_REG_SAR_MSB 0x39
#define SX9310_REG_SAR_LSB 0x3a
#define SX9310_REG_I2CADDR 0x40
#define SX9310_REG_I2C_ADDR 0x40
#define SX9310_REG_PAUSE 0x41
#define SX9310_REG_WHOAMI 0x42
#define SX9310_WHOAMI_VALUE 0x01
#define SX9311_WHOAMI_VALUE 0x02
#define SX9310_REG_RESET 0x7f
#define SX9310_SOFT_RESET 0xde
#define SX9310_SCAN_PERIOD_MASK GENMASK(7, 4)
#define SX9310_SCAN_PERIOD_SHIFT 4
#define SX9310_COMPSTAT_MASK GENMASK(3, 0)
/* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */
#define SX9310_NUM_CHANNELS 4
#define SX9310_CHAN_ENABLED_MASK GENMASK(3, 0)
static_assert(SX9310_NUM_CHANNELS < BITS_PER_LONG);
struct sx9310_data {
/* Serialize access to registers and channel configuration */
......@@ -131,20 +121,24 @@ struct sx9310_data {
struct i2c_client *client;
struct iio_trigger *trig;
struct regmap *regmap;
struct regulator_bulk_data supplies[2];
/*
* Last reading of the proximity status for each channel.
* We only send an event to user space when this changes.
*/
bool prox_stat[SX9310_NUM_CHANNELS];
unsigned long chan_prox_stat;
bool trigger_enabled;
__be16 buffer[SX9310_NUM_CHANNELS +
4]; /* 64-bit data + 64-bit timestamp */
/* Ensure correct alignment of timestamp when present. */
struct {
__be16 channels[SX9310_NUM_CHANNELS];
s64 ts __aligned(8);
} buffer;
/* Remember enabled channels and sample rate during suspend. */
unsigned int suspend_ctrl0;
struct completion completion;
unsigned int chan_read, chan_event;
int channel_users[SX9310_NUM_CHANNELS];
int whoami;
unsigned long chan_read;
unsigned long chan_event;
unsigned int whoami;
};
static const struct iio_event_spec sx9310_events[] = {
......@@ -251,7 +245,7 @@ static const struct regmap_range sx9310_readable_reg_ranges[] = {
regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19),
regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2),
regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB),
regmap_reg_range(SX9310_REG_I2CADDR, SX9310_REG_WHOAMI),
regmap_reg_range(SX9310_REG_I2C_ADDR, SX9310_REG_WHOAMI),
regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET),
};
......@@ -285,15 +279,16 @@ static const struct regmap_config sx9310_regmap_config = {
};
static int sx9310_update_chan_en(struct sx9310_data *data,
unsigned int chan_read,
unsigned int chan_event)
unsigned long chan_read,
unsigned long chan_event)
{
int ret;
unsigned long channels = chan_read | chan_event;
if ((data->chan_read | data->chan_event) != (chan_read | chan_event)) {
if ((data->chan_read | data->chan_event) != channels) {
ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
SX9310_CHAN_ENABLED_MASK,
chan_read | chan_event);
SX9310_REG_PROX_CTRL0_SENSOREN_MASK,
channels);
if (ret)
return ret;
}
......@@ -328,11 +323,15 @@ static int sx9310_put_event_channel(struct sx9310_data *data, int channel)
static int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq)
{
if (!data->client->irq)
return 0;
return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq);
}
static int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq)
{
if (!data->client->irq)
return 0;
return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0);
}
......@@ -342,10 +341,10 @@ static int sx9310_read_prox_data(struct sx9310_data *data,
int ret;
ret = regmap_write(data->regmap, SX9310_REG_SENSOR_SEL, chan->channel);
if (ret < 0)
if (ret)
return ret;
return regmap_bulk_read(data->regmap, chan->address, val, 2);
return regmap_bulk_read(data->regmap, chan->address, val, sizeof(*val));
}
/*
......@@ -358,10 +357,10 @@ static int sx9310_wait_for_sample(struct sx9310_data *data)
unsigned int val;
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &val);
if (ret < 0)
if (ret)
return ret;
val = (val & SX9310_SCAN_PERIOD_MASK) >> SX9310_SCAN_PERIOD_SHIFT;
val = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, val);
msleep(sx9310_scan_period_table[val]);
......@@ -371,22 +370,22 @@ static int sx9310_wait_for_sample(struct sx9310_data *data)
static int sx9310_read_proximity(struct sx9310_data *data,
const struct iio_chan_spec *chan, int *val)
{
int ret = 0;
int ret;
__be16 rawval;
mutex_lock(&data->mutex);
ret = sx9310_get_read_channel(data, chan->channel);
if (ret < 0)
if (ret)
goto out;
ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
if (ret < 0)
if (ret)
goto out_put_channel;
mutex_unlock(&data->mutex);
if (data->client->irq > 0) {
if (data->client->irq) {
ret = wait_for_completion_interruptible(&data->completion);
reinit_completion(&data->completion);
} else {
......@@ -395,22 +394,22 @@ static int sx9310_read_proximity(struct sx9310_data *data,
mutex_lock(&data->mutex);
if (ret < 0)
if (ret)
goto out_disable_irq;
ret = sx9310_read_prox_data(data, chan, &rawval);
if (ret < 0)
if (ret)
goto out_disable_irq;
*val = sign_extend32(be16_to_cpu(rawval),
(chan->address == SX9310_REG_DIFF_MSB ? 11 : 15));
chan->address == SX9310_REG_DIFF_MSB ? 11 : 15);
ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
if (ret < 0)
if (ret)
goto out_put_channel;
ret = sx9310_put_read_channel(data, chan->channel);
if (ret < 0)
if (ret)
goto out;
mutex_unlock(&data->mutex);
......@@ -430,12 +429,13 @@ static int sx9310_read_proximity(struct sx9310_data *data,
static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2)
{
unsigned int regval;
int ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &regval);
int ret;
if (ret < 0)
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &regval);
if (ret)
return ret;
regval = (regval & SX9310_SCAN_PERIOD_MASK) >> SX9310_SCAN_PERIOD_SHIFT;
regval = FIELD_GET(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, regval);
*val = sx9310_samp_freq_table[regval].val;
*val2 = sx9310_samp_freq_table[regval].val2;
......@@ -482,9 +482,10 @@ static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
mutex_lock(&data->mutex);
ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0,
SX9310_SCAN_PERIOD_MASK,
i << SX9310_SCAN_PERIOD_SHIFT);
ret = regmap_update_bits(
data->regmap, SX9310_REG_PROX_CTRL0,
SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK,
FIELD_PREP(SX9310_REG_PROX_CTRL0_SCANPERIOD_MASK, i));
mutex_unlock(&data->mutex);
......@@ -515,10 +516,9 @@ static irqreturn_t sx9310_irq_handler(int irq, void *private)
iio_trigger_poll(data->trig);
/*
* Even if no event is enabled, we need to wake the thread to
* clear the interrupt state by reading SX9310_REG_IRQ_SRC. It
* is not possible to do that here because regmap_read takes a
* mutex.
* Even if no event is enabled, we need to wake the thread to clear the
* interrupt state by reading SX9310_REG_IRQ_SRC.
* It is not possible to do that here because regmap_read takes a mutex.
*/
return IRQ_WAKE_THREAD;
}
......@@ -529,32 +529,32 @@ static void sx9310_push_events(struct iio_dev *indio_dev)
unsigned int val, chan;
struct sx9310_data *data = iio_priv(indio_dev);
s64 timestamp = iio_get_time_ns(indio_dev);
unsigned long prox_changed;
/* Read proximity state on all channels */
ret = regmap_read(data->regmap, SX9310_REG_STAT0, &val);
if (ret < 0) {
if (ret) {
dev_err(&data->client->dev, "i2c transfer error in irq\n");
return;
}
for (chan = 0; chan < SX9310_NUM_CHANNELS; chan++) {
/*
* Only iterate over channels with changes on proximity status that have
* events enabled.
*/
prox_changed = (data->chan_prox_stat ^ val) & data->chan_event;
for_each_set_bit(chan, &prox_changed, SX9310_NUM_CHANNELS) {
int dir;
u64 ev;
bool new_prox = val & BIT(chan);
if (!(data->chan_event & BIT(chan)))
continue;
if (new_prox == data->prox_stat[chan])
/* No change on this channel. */
continue;
dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
dir = (val & BIT(chan)) ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
IIO_EV_TYPE_THRESH, dir);
iio_push_event(indio_dev, ev, timestamp);
data->prox_stat[chan] = new_prox;
}
data->chan_prox_stat = val;
}
static irqreturn_t sx9310_irq_thread_handler(int irq, void *private)
......@@ -567,12 +567,12 @@ static irqreturn_t sx9310_irq_thread_handler(int irq, void *private)
mutex_lock(&data->mutex);
ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
if (ret < 0) {
if (ret) {
dev_err(&data->client->dev, "i2c transfer error in irq\n");
goto out;
}
if (val & SX9310_EVENT_IRQ)
if (val & (SX9310_FAR_IRQ | SX9310_CLOSE_IRQ))
sx9310_push_events(indio_dev);
if (val & SX9310_CONVDONE_IRQ)
......@@ -600,6 +600,7 @@ static int sx9310_write_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir, int state)
{
struct sx9310_data *data = iio_priv(indio_dev);
unsigned int eventirq = SX9310_FAR_IRQ | SX9310_CLOSE_IRQ;
int ret;
/* If the state hasn't changed, there's nothing to do. */
......@@ -609,20 +610,20 @@ static int sx9310_write_event_config(struct iio_dev *indio_dev,
mutex_lock(&data->mutex);
if (state) {
ret = sx9310_get_event_channel(data, chan->channel);
if (ret < 0)
if (ret)
goto out_unlock;
if (!(data->chan_event & ~BIT(chan->channel))) {
ret = sx9310_enable_irq(data, SX9310_EVENT_IRQ);
if (ret < 0)
ret = sx9310_enable_irq(data, eventirq);
if (ret)
sx9310_put_event_channel(data, chan->channel);
}
} else {
ret = sx9310_put_event_channel(data, chan->channel);
if (ret < 0)
if (ret)
goto out_unlock;
if (!data->chan_event) {
ret = sx9310_disable_irq(data, SX9310_EVENT_IRQ);
if (ret < 0)
ret = sx9310_disable_irq(data, eventirq);
if (ret)
sx9310_get_event_channel(data, chan->channel);
}
}
......@@ -634,7 +635,7 @@ static int sx9310_write_event_config(struct iio_dev *indio_dev,
static struct attribute *sx9310_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL,
NULL
};
static const struct attribute_group sx9310_attribute_group = {
......@@ -661,7 +662,7 @@ static int sx9310_set_trigger_state(struct iio_trigger *trig, bool state)
ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ);
else if (!data->chan_read)
ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ);
if (ret < 0)
if (ret)
goto out;
data->trigger_enabled = state;
......@@ -690,13 +691,13 @@ static irqreturn_t sx9310_trigger_handler(int irq, void *private)
indio_dev->masklength) {
ret = sx9310_read_prox_data(data, &indio_dev->channels[bit],
&val);
if (ret < 0)
if (ret)
goto out;
data->buffer[i++] = val;
data->buffer.channels[i++] = val;
}
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
pf->timestamp);
out:
......@@ -710,13 +711,13 @@ static irqreturn_t sx9310_trigger_handler(int irq, void *private)
static int sx9310_buffer_preenable(struct iio_dev *indio_dev)
{
struct sx9310_data *data = iio_priv(indio_dev);
unsigned int channels = 0;
unsigned long channels = 0;
int bit, ret;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength)
channels |= BIT(indio_dev->channels[bit].channel);
__set_bit(indio_dev->channels[bit].channel, &channels);
ret = sx9310_update_chan_en(data, channels, data->chan_event);
mutex_unlock(&data->mutex);
......@@ -744,89 +745,77 @@ struct sx9310_reg_default {
u8 def;
};
#define SX_INIT(_reg, _def) \
{ \
.reg = SX9310_REG_##_reg, \
.def = _def, \
}
static const struct sx9310_reg_default sx9310_default_regs[] = {
SX_INIT(IRQ_MSK, 0x00),
SX_INIT(IRQ_FUNC, 0x00),
{ SX9310_REG_IRQ_MSK, 0x00 },
{ SX9310_REG_IRQ_FUNC, 0x00 },
/*
* The lower 4 bits should not be set as it enable sensors measurements.
* Turning the detection on before the configuration values are set to
* good values can cause the device to return erroneous readings.
*/
SX_INIT(PROX_CTRL0, SX9310_REG_PROX_CTRL0_PROXSTAT2),
SX_INIT(PROX_CTRL1, 0x00),
SX_INIT(PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_ALL |
SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC),
SX_INIT(PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 |
SX9310_REG_PROX_CTRL3_GAIN12_X4),
SX_INIT(PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST),
SX_INIT(PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL |
SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 |
SX9310_REG_PROX_CTRL5_RAWFILT_1P25),
SX_INIT(PROX_CTRL6, SX9310_REG_PROX_CTRL6_COMP_COMMON),
SX_INIT(PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 |
SX9310_REG_PROX_CTRL7_AVGPOSFILT_512),
SX_INIT(PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 |
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500),
SX_INIT(PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH12_28 |
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900),
SX_INIT(PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT |
SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_8 |
SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_8),
SX_INIT(PROX_CTRL11, 0x00),
SX_INIT(PROX_CTRL12, 0x00),
SX_INIT(PROX_CTRL13, 0x00),
SX_INIT(PROX_CTRL14, 0x00),
SX_INIT(PROX_CTRL15, 0x00),
SX_INIT(PROX_CTRL16, 0x00),
SX_INIT(PROX_CTRL17, 0x00),
SX_INIT(PROX_CTRL18, 0x00),
SX_INIT(PROX_CTRL19, 0x00),
SX_INIT(SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES |
SX9310_REG_SAR_CTRL0_SARHYST_8),
SX_INIT(SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250)),
SX_INIT(SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT),
{ SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS },
{ SX9310_REG_PROX_CTRL1, 0x00 },
{ SX9310_REG_PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 |
SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC },
{ SX9310_REG_PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 |
SX9310_REG_PROX_CTRL3_GAIN12_X4 },
{ SX9310_REG_PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST },
{ SX9310_REG_PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL |
SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 |
SX9310_REG_PROX_CTRL5_RAWFILT_1P25 },
{ SX9310_REG_PROX_CTRL6, SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT },
{ SX9310_REG_PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 |
SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 },
{ SX9310_REG_PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 |
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 },
{ SX9310_REG_PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH_28 |
SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 },
{ SX9310_REG_PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT |
SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 },
{ SX9310_REG_PROX_CTRL11, 0x00 },
{ SX9310_REG_PROX_CTRL12, 0x00 },
{ SX9310_REG_PROX_CTRL13, 0x00 },
{ SX9310_REG_PROX_CTRL14, 0x00 },
{ SX9310_REG_PROX_CTRL15, 0x00 },
{ SX9310_REG_PROX_CTRL16, 0x00 },
{ SX9310_REG_PROX_CTRL17, 0x00 },
{ SX9310_REG_PROX_CTRL18, 0x00 },
{ SX9310_REG_PROX_CTRL19, 0x00 },
{ SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES |
SX9310_REG_SAR_CTRL0_SARHYST_8 },
{ SX9310_REG_SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250) },
{ SX9310_REG_SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT },
};
/* Activate all channels and perform an initial compensation. */
static int sx9310_init_compensation(struct iio_dev *indio_dev)
{
struct sx9310_data *data = iio_priv(indio_dev);
int i, ret;
int ret;
unsigned int val;
unsigned int ctrl0;
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &ctrl0);
if (ret < 0)
if (ret)
return ret;
/* run the compensation phase on all channels */
ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0,
ctrl0 | SX9310_REG_PROX_CTRL0_EN_MASK);
if (ret < 0)
ctrl0 | SX9310_REG_PROX_CTRL0_SENSOREN_MASK);
if (ret)
return ret;
for (i = 100; i >= 0; i--) {
msleep(20);
ret = regmap_read(data->regmap, SX9310_REG_STAT1, &val);
if (ret < 0)
goto out;
if (!(val & SX9310_COMPSTAT_MASK))
break;
}
if (i < 0) {
dev_err(&data->client->dev,
"initial compensation timed out: 0x%02x", val);
ret = -ETIMEDOUT;
ret = regmap_read_poll_timeout(data->regmap, SX9310_REG_STAT1, val,
!(val & SX9310_REG_STAT1_COMPSTAT_MASK),
20000, 2000000);
if (ret) {
if (ret == -ETIMEDOUT)
dev_err(&data->client->dev,
"initial compensation timed out: 0x%02x\n",
val);
return ret;
}
out:
regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
return ret;
}
......@@ -839,21 +828,21 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
unsigned int i, val;
ret = regmap_write(data->regmap, SX9310_REG_RESET, SX9310_SOFT_RESET);
if (ret < 0)
if (ret)
return ret;
usleep_range(1000, 2000); /* power-up time is ~1ms. */
/* Clear reset interrupt state by reading SX9310_REG_IRQ_SRC. */
ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val);
if (ret < 0)
if (ret)
return ret;
/* Program some sane defaults. */
for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) {
initval = &sx9310_default_regs[i];
ret = regmap_write(data->regmap, initval->reg, initval->def);
if (ret < 0)
if (ret)
return ret;
}
......@@ -862,24 +851,15 @@ static int sx9310_init_device(struct iio_dev *indio_dev)
static int sx9310_set_indio_dev_name(struct device *dev,
struct iio_dev *indio_dev,
const struct i2c_device_id *id, int whoami)
unsigned int whoami)
{
const struct acpi_device_id *acpi_id;
/* id will be NULL when enumerated via ACPI */
if (id) {
if (id->driver_data != whoami)
dev_err(dev, "WHOAMI does not match i2c_device_id: %s",
id->name);
} else if (ACPI_HANDLE(dev)) {
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!acpi_id)
return -ENODEV;
if (acpi_id->driver_data != whoami)
dev_err(dev, "WHOAMI does not match acpi_device_id: %s",
acpi_id->id);
} else
unsigned int long ddata;
ddata = (uintptr_t)device_get_match_data(dev);
if (ddata != whoami) {
dev_err(dev, "WHOAMI does not match device data: %u\n", whoami);
return -ENODEV;
}
switch (whoami) {
case SX9310_WHOAMI_VALUE:
......@@ -889,26 +869,35 @@ static int sx9310_set_indio_dev_name(struct device *dev,
indio_dev->name = "sx9311";
break;
default:
dev_err(dev, "unexpected WHOAMI response: %u", whoami);
dev_err(dev, "unexpected WHOAMI response: %u\n", whoami);
return -ENODEV;
}
return 0;
}
static int sx9310_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static void sx9310_regulator_disable(void *_data)
{
struct sx9310_data *data = _data;
regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
}
static int sx9310_probe(struct i2c_client *client)
{
int ret;
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct sx9310_data *data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (indio_dev == NULL)
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->client = client;
data->supplies[0].supply = "vdd";
data->supplies[1].supply = "svdd";
mutex_init(&data->mutex);
init_completion(&data->completion);
......@@ -916,19 +905,32 @@ static int sx9310_probe(struct i2c_client *client,
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
data->supplies);
if (ret)
return ret;
ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
if (ret)
return ret;
/* Must wait for Tpor time after initial power up */
usleep_range(1000, 1100);
ret = devm_add_action_or_reset(dev, sx9310_regulator_disable, data);
if (ret)
return ret;
ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &data->whoami);
if (ret < 0) {
dev_err(&client->dev, "error in reading WHOAMI register: %d",
ret);
if (ret) {
dev_err(dev, "error in reading WHOAMI register: %d", ret);
return ret;
}
ret = sx9310_set_indio_dev_name(&client->dev, indio_dev, id,
data->whoami);
if (ret < 0)
ret = sx9310_set_indio_dev_name(dev, indio_dev, data->whoami);
if (ret)
return ret;
ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(&client->dev));
ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(dev));
indio_dev->channels = sx9310_channels;
indio_dev->num_channels = ARRAY_SIZE(sx9310_channels);
indio_dev->info = &sx9310_info;
......@@ -936,41 +938,41 @@ static int sx9310_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
ret = sx9310_init_device(indio_dev);
if (ret < 0)
if (ret)
return ret;
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
ret = devm_request_threaded_irq(dev, client->irq,
sx9310_irq_handler,
sx9310_irq_thread_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
IRQF_ONESHOT,
"sx9310_event", indio_dev);
if (ret < 0)
if (ret)
return ret;
data->trig =
devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
indio_dev->name, indio_dev->id);
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
indio_dev->id);
if (!data->trig)
return -ENOMEM;
data->trig->dev.parent = &client->dev;
data->trig->dev.parent = dev;
data->trig->ops = &sx9310_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
ret = devm_iio_trigger_register(&client->dev, data->trig);
ret = devm_iio_trigger_register(dev, data->trig);
if (ret)
return ret;
}
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
sx9310_trigger_handler,
&sx9310_buffer_setup_ops);
if (ret < 0)
if (ret)
return ret;
return devm_iio_device_register(&client->dev, indio_dev);
return devm_iio_device_register(dev, indio_dev);
}
static int __maybe_unused sx9310_suspend(struct device *dev)
......@@ -985,11 +987,10 @@ static int __maybe_unused sx9310_suspend(struct device *dev)
mutex_lock(&data->mutex);
ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0,
&data->suspend_ctrl0);
if (ret)
goto out;
ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_EN_MASK;
ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_SENSOREN_MASK;
ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0);
if (ret)
goto out;
......@@ -1017,10 +1018,11 @@ static int __maybe_unused sx9310_resume(struct device *dev)
out:
mutex_unlock(&data->mutex);
if (ret)
return ret;
enable_irq(data->client->irq);
return ret;
return 0;
}
static const struct dev_pm_ops sx9310_pm_ops = {
......@@ -1030,32 +1032,32 @@ static const struct dev_pm_ops sx9310_pm_ops = {
static const struct acpi_device_id sx9310_acpi_match[] = {
{ "STH9310", SX9310_WHOAMI_VALUE },
{ "STH9311", SX9311_WHOAMI_VALUE },
{},
{}
};
MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match);
static const struct of_device_id sx9310_of_match[] = {
{ .compatible = "semtech,sx9310" },
{ .compatible = "semtech,sx9311" },
{},
{ .compatible = "semtech,sx9310", (void *)SX9310_WHOAMI_VALUE },
{ .compatible = "semtech,sx9311", (void *)SX9311_WHOAMI_VALUE },
{}
};
MODULE_DEVICE_TABLE(of, sx9310_of_match);
static const struct i2c_device_id sx9310_id[] = {
{ "sx9310", SX9310_WHOAMI_VALUE },
{ "sx9311", SX9311_WHOAMI_VALUE },
{},
{}
};
MODULE_DEVICE_TABLE(i2c, sx9310_id);
static struct i2c_driver sx9310_driver = {
.driver = {
.name = "sx9310",
.acpi_match_table = ACPI_PTR(sx9310_acpi_match),
.of_match_table = of_match_ptr(sx9310_of_match),
.acpi_match_table = sx9310_acpi_match,
.of_match_table = sx9310_of_match,
.pm = &sx9310_pm_ops,
},
.probe = sx9310_probe,
.probe_new = sx9310_probe,
.id_table = sx9310_id,
};
module_i2c_driver(sx9310_driver);
......
......@@ -10,7 +10,9 @@
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/of.h>
......@@ -58,6 +60,8 @@
/* Control register address - volatile */
#define MLX90632_REG_CONTROL 0x3001 /* Control Register address */
#define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */
#define MLX90632_CFG_MTYP_MASK GENMASK(8, 4) /* Meas select Mask */
/* PowerModes statuses */
#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1)
#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */
......@@ -65,6 +69,18 @@
#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */
#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/
/* Measurement types */
#define MLX90632_MTYP_MEDICAL 0
#define MLX90632_MTYP_EXTENDED 17
/* Measurement type select*/
#define MLX90632_MTYP_STATUS(ctrl_val) (ctrl_val << 4)
#define MLX90632_MTYP_STATUS_MEDICAL MLX90632_MTYP_STATUS(MLX90632_MTYP_MEDICAL)
#define MLX90632_MTYP_STATUS_EXTENDED MLX90632_MTYP_STATUS(MLX90632_MTYP_EXTENDED)
/* I2C command register - volatile */
#define MLX90632_REG_I2C_CMD 0x3005 /* I2C command Register address */
/* Device status register - volatile */
#define MLX90632_REG_STATUS 0x3fff /* Device status register */
#define MLX90632_STAT_BUSY BIT(10) /* Device busy indicator */
......@@ -78,26 +94,53 @@
#define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1)
#define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2)
/* Name important RAM_MEAS channels */
#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1 MLX90632_RAM_3(17)
#define MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2 MLX90632_RAM_3(18)
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_1 MLX90632_RAM_1(17)
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_2 MLX90632_RAM_2(17)
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_3 MLX90632_RAM_1(18)
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_4 MLX90632_RAM_2(18)
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_5 MLX90632_RAM_1(19)
#define MLX90632_RAM_DSP5_EXTENDED_OBJECT_6 MLX90632_RAM_2(19)
/* Magic constants */
#define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */
#define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */
#define MLX90632_ID_EXTENDED 0x0505 /* EEPROM DSPv5 Extended range device id */
#define MLX90632_ID_MASK GENMASK(14, 0) /* DSP version and device ID in EE_VERSION */
#define MLX90632_DSP_VERSION 5 /* DSP version */
#define MLX90632_DSP_MASK GENMASK(7, 0) /* DSP version in EE_VERSION */
#define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */
#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */
#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */
#define MLX90632_MAX_MEAS_NUM 31 /**< Maximum measurements in list */
#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */
#define MLX90632_REF_12 12LL /* ResCtrlRef value of Ch 1 or Ch 2 */
#define MLX90632_REF_3 12LL /* ResCtrlRef value of Channel 3 */
#define MLX90632_MAX_MEAS_NUM 31 /* Maximum measurements in list */
#define MLX90632_SLEEP_DELAY_MS 3000 /* Autosleep delay */
#define MLX90632_EXTENDED_LIMIT 27000 /* Extended mode raw value limit */
/**
* struct mlx90632_data - private data for the MLX90632 device
* @client: I2C client of the device
* @lock: Internal mutex for multiple reads for single measurement
* @regmap: Regmap of the device
* @emissivity: Object emissivity from 0 to 1000 where 1000 = 1.
* @mtyp: Measurement type physical sensor configuration for extended range
* calculations
* @object_ambient_temperature: Ambient temperature at object (might differ of
* the ambient temperature of sensor.
*/
struct mlx90632_data {
struct i2c_client *client;
struct mutex lock; /* Multiple reads for single measurement */
struct mutex lock;
struct regmap *regmap;
u16 emissivity;
u8 mtyp;
u32 object_ambient_temperature;
};
static const struct regmap_range mlx90632_volatile_reg_range[] = {
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
regmap_reg_range(MLX90632_RAM_1(0),
MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
......@@ -113,6 +156,7 @@ static const struct regmap_range mlx90632_read_reg_range[] = {
regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR),
regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb),
regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL),
regmap_reg_range(MLX90632_REG_I2C_CMD, MLX90632_REG_I2C_CMD),
regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS),
regmap_reg_range(MLX90632_RAM_1(0),
MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)),
......@@ -173,25 +217,19 @@ static s32 mlx90632_pwr_continuous(struct regmap *regmap)
*/
static int mlx90632_perform_measurement(struct mlx90632_data *data)
{
int ret, tries = 100;
unsigned int reg_status;
int ret;
ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS,
MLX90632_STAT_DATA_RDY, 0);
if (ret < 0)
return ret;
while (tries-- > 0) {
ret = regmap_read(data->regmap, MLX90632_REG_STATUS,
&reg_status);
if (ret < 0)
return ret;
if (reg_status & MLX90632_STAT_DATA_RDY)
break;
usleep_range(10000, 11000);
}
ret = regmap_read_poll_timeout(data->regmap, MLX90632_REG_STATUS, reg_status,
!(reg_status & MLX90632_STAT_DATA_RDY), 10000,
100 * 10000);
if (tries < 0) {
if (ret < 0) {
dev_err(&data->client->dev, "data not ready");
return -ETIMEDOUT;
}
......@@ -199,6 +237,26 @@ static int mlx90632_perform_measurement(struct mlx90632_data *data)
return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2;
}
static int mlx90632_set_meas_type(struct regmap *regmap, u8 type)
{
int ret;
if ((type != MLX90632_MTYP_MEDICAL) && (type != MLX90632_MTYP_EXTENDED))
return -EINVAL;
ret = regmap_write(regmap, MLX90632_REG_I2C_CMD, MLX90632_RESET_CMD);
if (ret < 0)
return ret;
ret = regmap_write_bits(regmap, MLX90632_REG_CONTROL,
(MLX90632_CFG_MTYP_MASK | MLX90632_CFG_PWR_MASK),
(MLX90632_MTYP_STATUS(type) | MLX90632_PWR_STATUS_HALT));
if (ret < 0)
return ret;
return mlx90632_pwr_continuous(regmap);
}
static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new,
uint8_t *channel_old)
{
......@@ -300,6 +358,97 @@ static int mlx90632_read_all_channel(struct mlx90632_data *data,
return ret;
}
static int mlx90632_read_ambient_raw_extended(struct regmap *regmap,
s16 *ambient_new_raw, s16 *ambient_old_raw)
{
unsigned int read_tmp;
int ret;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_1, &read_tmp);
if (ret < 0)
return ret;
*ambient_new_raw = (s16)read_tmp;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_AMBIENT_2, &read_tmp);
if (ret < 0)
return ret;
*ambient_old_raw = (s16)read_tmp;
return 0;
}
static int mlx90632_read_object_raw_extended(struct regmap *regmap, s16 *object_new_raw)
{
unsigned int read_tmp;
s32 read;
int ret;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_1, &read_tmp);
if (ret < 0)
return ret;
read = (s16)read_tmp;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_2, &read_tmp);
if (ret < 0)
return ret;
read = read - (s16)read_tmp;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_3, &read_tmp);
if (ret < 0)
return ret;
read = read - (s16)read_tmp;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_4, &read_tmp);
if (ret < 0)
return ret;
read = (read + (s16)read_tmp) / 2;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_5, &read_tmp);
if (ret < 0)
return ret;
read = read + (s16)read_tmp;
ret = regmap_read(regmap, MLX90632_RAM_DSP5_EXTENDED_OBJECT_6, &read_tmp);
if (ret < 0)
return ret;
read = read + (s16)read_tmp;
if (read > S16_MAX || read < S16_MIN)
return -ERANGE;
*object_new_raw = read;
return 0;
}
static int mlx90632_read_all_channel_extended(struct mlx90632_data *data, s16 *object_new_raw,
s16 *ambient_new_raw, s16 *ambient_old_raw)
{
s32 ret, meas;
mutex_lock(&data->lock);
ret = mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_EXTENDED);
if (ret < 0)
goto read_unlock;
ret = read_poll_timeout(mlx90632_perform_measurement, meas, meas == 19,
50000, 800000, false, data);
if (ret != 0)
goto read_unlock;
ret = mlx90632_read_object_raw_extended(data->regmap, object_new_raw);
if (ret < 0)
goto read_unlock;
ret = mlx90632_read_ambient_raw_extended(data->regmap, ambient_new_raw, ambient_old_raw);
read_unlock:
(void) mlx90632_set_meas_type(data->regmap, MLX90632_MTYP_MEDICAL);
mutex_unlock(&data->lock);
return ret;
}
static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb,
s32 *reg_value)
{
......@@ -354,9 +503,23 @@ static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw,
return div64_s64((tmp << 19ULL), 1000LL);
}
static s64 mlx90632_preprocess_temp_obj_extended(s16 object_new_raw, s16 ambient_new_raw,
s16 ambient_old_raw, s16 Ka)
{
s64 VR_IR, kKa, tmp;
kKa = ((s64)Ka * 1000LL) >> 10ULL;
VR_IR = (s64)ambient_old_raw * 1000000LL +
kKa * div64_s64((s64)ambient_new_raw * 1000LL,
MLX90632_REF_3);
tmp = div64_s64(
div64_s64((s64) object_new_raw * 1000000000000LL, MLX90632_REF_12),
VR_IR);
return div64_s64(tmp << 19ULL, 1000LL);
}
static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
s32 P_T, s32 P_R, s32 P_G, s32 P_O,
s16 Gb)
s32 P_T, s32 P_R, s32 P_G, s32 P_O, s16 Gb)
{
s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum;
......@@ -374,11 +537,11 @@ static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
}
static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
s64 TAdut, s32 Fa, s32 Fb,
s64 TAdut, s64 TAdut4, s32 Fa, s32 Fb,
s32 Ga, s16 Ha, s16 Hb,
u16 emissivity)
{
s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr;
s64 calcedKsTO, calcedKsTA, ir_Alpha, Alpha_corr;
s64 Ha_customer, Hb_customer;
Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
......@@ -393,36 +556,66 @@ static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL);
Alpha_corr = div64_s64(Alpha_corr, 1000LL);
ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr);
TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) *
(div64_s64(TAdut, 10000LL) + 27315) *
(div64_s64(TAdut, 10000LL) + 27315) *
(div64_s64(TAdut, 10000LL) + 27315);
return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4))
- 27315 - Hb_customer) * 10;
}
static s64 mlx90632_calc_ta4(s64 TAdut, s64 scale)
{
return (div64_s64(TAdut, scale) + 27315) *
(div64_s64(TAdut, scale) + 27315) *
(div64_s64(TAdut, scale) + 27315) *
(div64_s64(TAdut, scale) + 27315);
}
static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb,
s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb,
u16 tmp_emi)
{
s64 kTA, kTA0, TAdut;
s64 kTA, kTA0, TAdut, TAdut4;
s64 temp = 25000;
s8 i;
kTA = (Ea * 1000LL) >> 16LL;
kTA0 = (Eb * 1000LL) >> 8LL;
TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL;
TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
/* Iterations of calculation as described in datasheet */
for (i = 0; i < 5; ++i) {
temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut,
temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TAdut4,
Fa, Fb, Ga, Ha, Hb,
tmp_emi);
}
return temp;
}
static s32 mlx90632_calc_temp_object_extended(s64 object, s64 ambient, s64 reflected,
s32 Ea, s32 Eb, s32 Fa, s32 Fb, s32 Ga,
s16 Ha, s16 Hb, u16 tmp_emi)
{
s64 kTA, kTA0, TAdut, TAdut4, Tr4, TaTr4;
s64 temp = 25000;
s8 i;
kTA = (Ea * 1000LL) >> 16LL;
kTA0 = (Eb * 1000LL) >> 8LL;
TAdut = div64_s64((ambient - kTA0) * 1000000LL, kTA) + 25 * 1000000LL;
Tr4 = mlx90632_calc_ta4(reflected, 10);
TAdut4 = mlx90632_calc_ta4(TAdut, 10000LL);
TaTr4 = Tr4 - div64_s64(Tr4 - TAdut4, tmp_emi) * 1000;
/* Iterations of calculation as described in datasheet */
for (i = 0; i < 5; ++i) {
temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, TaTr4,
Fa / 2, Fb, Ga, Ha, Hb,
tmp_emi);
}
return temp;
}
static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
{
s32 ret;
......@@ -470,6 +663,26 @@ static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val)
if (ret < 0)
return ret;
if (object_new_raw > MLX90632_EXTENDED_LIMIT &&
data->mtyp == MLX90632_MTYP_EXTENDED) {
ret = mlx90632_read_all_channel_extended(data, &object_new_raw,
&ambient_new_raw, &ambient_old_raw);
if (ret < 0)
return ret;
/* Use extended mode calculations */
ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
ambient_old_raw, Gb);
object = mlx90632_preprocess_temp_obj_extended(object_new_raw,
ambient_new_raw,
ambient_old_raw, Ka);
*val = mlx90632_calc_temp_object_extended(object, ambient,
data->object_ambient_temperature,
Ea, Eb, Fa, Fb, Ga,
Ha, Hb, data->emissivity);
return 0;
}
ambient = mlx90632_preprocess_temp_amb(ambient_new_raw,
ambient_old_raw, Gb);
object = mlx90632_preprocess_temp_obj(object_new_raw,
......@@ -643,6 +856,7 @@ static int mlx90632_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
mlx90632->client = client;
mlx90632->regmap = regmap;
mlx90632->mtyp = MLX90632_MTYP_MEDICAL;
mutex_init(&mlx90632->lock);
indio_dev->name = id->name;
......@@ -662,15 +876,20 @@ static int mlx90632_probe(struct i2c_client *client,
dev_err(&client->dev, "read of version failed: %d\n", ret);
return ret;
}
read = read & MLX90632_ID_MASK;
if (read == MLX90632_ID_MEDICAL) {
dev_dbg(&client->dev,
"Detected Medical EEPROM calibration %x\n", read);
} else if (read == MLX90632_ID_CONSUMER) {
dev_dbg(&client->dev,
"Detected Consumer EEPROM calibration %x\n", read);
} else if (read == MLX90632_ID_EXTENDED) {
dev_dbg(&client->dev,
"Detected Extended range EEPROM calibration %x\n", read);
mlx90632->mtyp = MLX90632_MTYP_EXTENDED;
} else if ((read & MLX90632_DSP_MASK) == MLX90632_DSP_VERSION) {
dev_dbg(&client->dev,
"Detected Unknown EEPROM calibration %x\n", read);
"Detected Unknown EEPROM calibration %x\n", read);
} else {
dev_err(&client->dev,
"Wrong DSP version %x (expected %x)\n",
......@@ -679,6 +898,7 @@ static int mlx90632_probe(struct i2c_client *client,
}
mlx90632->emissivity = 1000;
mlx90632->object_ambient_temperature = 25000; /* 25 degrees milliCelsius */
pm_runtime_disable(&client->dev);
ret = pm_runtime_set_active(&client->dev);
......
......@@ -9,7 +9,7 @@ The aim is to fill the gap between the somewhat similar hwmon and
input subsystems. Hwmon is very much directed at low sample rate
sensors used in applications such as fan speed control and temperature
measurement. Input is, as its name suggests focused on input
devices. In some cases there is considerable overlap between these and
devices. In some cases, there is considerable overlap between these and
IIO.
A typical device falling into this category would be connected via SPI
......@@ -38,7 +38,7 @@ series and Analog Devices ADXL345 accelerometers. Each buffer supports
polling to establish when data is available.
* Trigger and software buffer support. In many data analysis
applications it it useful to be able to capture data based on some
applications it is useful to be able to capture data based on some
external signal (trigger). These triggers might be a data ready
signal, a gpio line connected to some external system or an on
processor periodic interrupt. A single trigger may initialize data
......
......@@ -397,7 +397,6 @@ static int ad9834_probe(struct spi_device *spi)
struct regulator *reg;
int ret;
reg = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(reg))
return PTR_ERR(reg);
......
......@@ -40,7 +40,7 @@ enum ad7793_bias_voltage {
* enum ad7793_refsel - AD7793 reference voltage selection
* @AD7793_REFSEL_REFIN1: External reference applied between REFIN1(+)
* and REFIN1(-).
* @AD7793_REFSEL_REFIN2: External reference applied between REFIN2(+) and
* @AD7793_REFSEL_REFIN2: External reference applied between REFIN2(+)
* and REFIN1(-). Only valid for AD7795/AD7796.
* @AD7793_REFSEL_INTERNAL: Internal 1.17 V reference.
*/
......
......@@ -94,6 +94,7 @@ enum iio_modifier {
IIO_MOD_PM10,
IIO_MOD_ETHANOL,
IIO_MOD_H2,
IIO_MOD_O2,
};
enum iio_event_type {
......
......@@ -119,6 +119,7 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_PM2P5] = "pm2p5",
[IIO_MOD_PM4] = "pm4",
[IIO_MOD_PM10] = "pm10",
[IIO_MOD_O2] = "o2",
};
static bool event_is_known(struct iio_event_data *event)
......@@ -211,6 +212,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_MOD_PM2P5:
case IIO_MOD_PM4:
case IIO_MOD_PM10:
case IIO_MOD_O2:
break;
default:
return false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment