Commit 8598bb4c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-5.12a' of...

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

Jonathan writes:

First set of IIO new device support, cleanups etc for 5.12

Includes one immutable branch, to support some qcom-vadc patches
going through IIO and thermal.

Late rebase to drop a patch that should go through the hid tree.

New device support:
* adi,ad5766
  - New driver supporting AD5766 and AD5767 16 channel DACs.
* adi,ad7476
  - Support for LTC2314-14 14 bit ADC (trivial to add)
* hid-sensors-hinge
  - New driver including HID custom sensor support.
* invensense,mpu6050
  - Add support for the MPU-6880 (chip info all that is needed)
* memsic,ms5637
  - Add support for ms5803 device after a bunch of rework.
* xilinx-xadc
  - Add support for Ultrascale System Monitor.
* yamaha,yas530
  - New driver for this magnetometer supporting YAS530, YAS532 adn YAS 533.

Dt-binding conversions to yaml
* invensense,mpu3050
* invensense,mpu6050

Cleanups and minor features
* core
  - Copy iio_info.attrs->is_visible along with the attrs themselves.
  - Handle enumerate properties with gaps (i.e. reserved values in
    the middle of otherwise used values).
  - Add an of_iio_channel_get_by_name() function.
* adi,adf4350
  - Drop an unnecessary NULL check.
* amstaos,tsl2583
  - Use DIV_ROUND_CLOSEST in place of open coding.
* avago,apds9960
  - Add MSHW0184 ACPI id seen in the Microsoft Surface Book 3 and Surface
    Pro 7.
* bosch,bmc150_magn
  - Basic regulator support.
* bosch,bme680
  - Use DIV_ROUND_CLOSEST in place of opencoding.
* bosch,bmg160
  - Basic regulator support.
* hid-sensors
  - Add timestamp channels to all sensors types.
* kionix,kxcjk1013
  - Basic regulator support.
* memsic
  - Fix ordering in trivial-device.yaml
* microchip,mcp4725
  - More flexible restrictions in DT binding.
* plantower,pms7003
  - Fix comma that should be semicolon.
* qcom-vadc
  - Refactors to support addition of ADC-TM5 driver
  - Addition of a fixp_linear_interpolate function to support this common
    operation.
* sprd,sc27xx_adc
  - Use DIV_ROUND_CLOSEST in place of opencoding.
* st,ab8500-adc
  - Enable non-hw-conversion as AB505 doesn't support it.
* st,stm32-adc
  - Drop unneeded NULL check.
* st,stm32-dfsdm
  - Drop unneeded NULL check.
* st,vl6180
  - Use DIV_ROUND_CLOSEST in place of opencoding.
* xilinx-xadc
  - Local var for &pdev->dev to avoid excessive repetition.
  - devm_ throughout and drop remove()

* tag 'iio-for-5.12a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (59 commits)
  iio: adc: stm32-dfsdm: Remove redundant null check before clk_disable_unprepare
  iio:pressure:ms5637: add ms5803 support
  iio:common:ms_sensors:ms_sensors_i2c: add support for alternative PROM layout
  iio:common:ms_sensors:ms_sensors_i2c: rework CRC calculation helper
  iio:pressure:ms5637: limit available sample frequencies
  iio:pressure:ms5637: introduce hardware differentiation
  dt-bindings: trivial-devices: reorder memsic devices
  iio: dac: ad5766: add driver support for AD5766
  Documentation/ABI/testing: Add documentation for AD5766 new ABI
  dt-bindings: iio: dac: AD5766 yaml documentation
  iio: hid-sensor-rotation: Add timestamp channel
  iio: hid-sensor-incl-3d: Add timestamp channel
  iio: hid-sensor-magn-3d: Add timestamp channel
  iio: hid-sensor-als: Add timestamp channel
  iio: hid-sensor-gyro-3d: Add timestamp channel
  iio: hid-sensor-accel-3d: Add timestamp channel for gravity sensor
  iio: magnetometer: bmc150: Add rudimentary regulator support
  dt-bindings: iio: magnetometer: bmc150: Document regulator supplies
  iio: Handle enumerated properties with gaps
  iio:Documentation: Add documentation for hinge sensor channels
  ...
parents 3dba1da3 1994a922
...@@ -198,6 +198,7 @@ Description: ...@@ -198,6 +198,7 @@ Description:
Units after application of scale and offset are m/s^2. Units after application of scale and offset are m/s^2.
What: /sys/bus/iio/devices/iio:deviceX/in_angl_raw What: /sys/bus/iio/devices/iio:deviceX/in_angl_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglY_raw
KernelVersion: 4.17 KernelVersion: 4.17
Contact: linux-iio@vger.kernel.org Contact: linux-iio@vger.kernel.org
Description: Description:
...@@ -1812,3 +1813,13 @@ Contact: linux-iio@vger.kernel.org ...@@ -1812,3 +1813,13 @@ Contact: linux-iio@vger.kernel.org
Description: Description:
Unscaled light intensity according to CIE 1931/DIN 5033 color space. Unscaled light intensity according to CIE 1931/DIN 5033 color space.
Units after application of scale are nano nanowatts per square meter. Units after application of scale are nano nanowatts per square meter.
What: /sys/bus/iio/devices/iio:deviceX/in_anglY_label
KernelVersion: 5.12
Contact: linux-iio@vger.kernel.org
Description:
Optional symbolic label for channel Y.
For Intel hid hinge sensor, the label values are:
hinge, keyboard, screen. It means the three channels
each correspond respectively to hinge angle, keyboard angle,
and screen angle.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_dither_enable
KernelVersion: 5.12
Contact: linux-iio@vger.kernel.org
Description:
Dither enable. Write 1 to enable dither or 0 to disable it.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_dither_invert
KernelVersion: 5.12
Contact: linux-iio@vger.kernel.org
Description:
Inverts the dither applied to the selected DAC channel. Dither is not
inverted by default. Write "1" to invert dither.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_dither_scale_available
KernelVersion: 5.12
Contact: linux-iio@vger.kernel.org
Description:
Returns possible scalings available for the current channel.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_dither_scale
KernelVersion: 5.12
Contact: linux-iio@vger.kernel.org
Description:
Scales the dither before it is applied to the selected channel.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_dither_source
KernelVersion: 5.12
Contact: linux-iio@vger.kernel.org
Description:
Selects dither source applied to the selected channel. Write "0" to
select N0 source, write "1" to select N1 source.
...@@ -20,6 +20,9 @@ properties: ...@@ -20,6 +20,9 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
vdd-supply: true
vddio-supply: true
mount-matrix: mount-matrix:
description: an optional 3x3 mounting rotation matrix. description: an optional 3x3 mounting rotation matrix.
......
Xilinx XADC device driver Xilinx XADC device driver
This binding document describes the bindings for both of them since the This binding document describes the bindings for the Xilinx 7 Series XADC as well
bindings are very similar. The Xilinx XADC is a ADC that can be found in the as the UltraScale/UltraScale+ System Monitor.
series 7 FPGAs from Xilinx. The XADC has a DRP interface for communication.
Currently two different frontends for the DRP interface exist. One that is only The Xilinx XADC is an ADC that can be found in the Series 7 FPGAs from Xilinx.
available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The The XADC has a DRP interface for communication. Currently two different
other one is available on all series 7 platforms and is a softmacro with a AXI frontends for the DRP interface exist. One that is only available on the ZYNQ
interface. This binding document describes the bindings for both of them since family as a hardmacro in the SoC portion of the ZYNQ. The other one is available
the bindings are very similar. on all series 7 platforms and is a softmacro with a AXI interface. This binding
document describes the bindings for both of them since the bindings are very
similar.
The Xilinx System Monitor is an ADC that is found in the UltraScale and
UltraScale+ FPGAs from Xilinx. The System Monitor provides a DRP interface for
communication. Xilinx provides a standard IP core that can be used to access the
System Monitor through an AXI interface in the FPGA fabric. This IP core is
called the Xilinx System Management Wizard. This document describes the bindings
for this IP.
Required properties: Required properties:
- compatible: Should be one of - compatible: Should be one of
...@@ -15,11 +24,14 @@ Required properties: ...@@ -15,11 +24,14 @@ Required properties:
configuration interface to interface to the XADC hardmacro. configuration interface to interface to the XADC hardmacro.
* "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to * "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to
interface to the XADC hardmacro. interface to the XADC hardmacro.
* "xlnx,system-management-wiz-1.3": When using the
Xilinx System Management Wizard fabric IP core to access the
UltraScale and UltraScale+ System Monitor.
- reg: Address and length of the register set for the device - reg: Address and length of the register set for the device
- interrupts: Interrupt for the XADC control interface. - interrupts: Interrupt for the XADC control interface.
- clocks: When using the ZYNQ this must be the ZYNQ PCAP clock, - clocks: When using the ZYNQ this must be the ZYNQ PCAP clock,
when using the AXI-XADC pcore this must be the clock that provides the when using the axi-xadc or the axi-system-management-wizard this must be
clock to the AXI bus interface of the core. the clock that provides the clock to the AXI bus interface of the core.
Optional properties: Optional properties:
- xlnx,external-mux: - xlnx,external-mux:
...@@ -110,3 +122,20 @@ Examples: ...@@ -110,3 +122,20 @@ Examples:
}; };
}; };
}; };
adc@80000000 {
compatible = "xlnx,system-management-wiz-1.3";
reg = <0x80000000 0x1000>;
interrupts = <0 81 4>;
interrupt-parent = <&gic>;
clocks = <&fpga1_clk>;
xlnx,channels {
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
xlnx,bipolar;
};
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2020 Analog Devices Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/dac/adi,ad5766.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD5766 DAC device driver
maintainers:
- Cristian Pop <cristian.pop@analog.com>
description: |
Bindings for the Analog Devices AD5766 current DAC device. Datasheet can be
found here:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad5766-5767.pdf
properties:
compatible:
enum:
- adi,ad5766
- adi,ad5767
output-range-microvolts:
description: Select converter output range.
reg:
maxItems: 1
spi-max-frequency:
maximum: 1000000
spi-cpol: true
reset-gpios:
description: GPIO spec for the RESET pin. As the line is active low, it
should be marked GPIO_ACTIVE_LOW.
maxItems: 1
required:
- compatible
- output-range-microvolts
- reg
- spi-max-frequency
- spi-cpol
additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ad5766@0 {
compatible = "adi,ad5766";
output-range-microvolts = <(-5000) 5000>;
reg = <0>;
spi-cpol;
spi-max-frequency = <1000000>;
reset-gpios = <&gpio 22 0>;
};
};
...@@ -39,20 +39,39 @@ properties: ...@@ -39,20 +39,39 @@ properties:
allOf: allOf:
- if: - if:
not: properties:
properties: compatible:
compatible: contains:
contains: const: microchip,mcp4725
const: microchip,mcp4726
then: then:
properties: properties:
vref-supply: false vref-supply: false
required:
- vdd-supply
- if:
properties:
compatible:
contains:
const: microchip,mcp4726
then:
anyOf:
- required:
- vdd-supply
- required:
- vref-supply
- if:
not:
required:
- vref-supply
then:
properties:
microchip,vref-buffered: false microchip,vref-buffered: false
required: required:
- compatible - compatible
- reg - reg
- vdd-supply
additionalProperties: false additionalProperties: false
......
...@@ -19,6 +19,9 @@ properties: ...@@ -19,6 +19,9 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
vdd-supply: true
vddio-supply: true
interrupts: interrupts:
minItems: 1 minItems: 1
description: description:
......
Invensense MPU-3050 Gyroscope device tree bindings
Required properties:
- compatible : should be "invensense,mpu3050"
- reg : the I2C address of the sensor
Optional properties:
- interrupts : interrupt mapping for the trigger interrupt from the
internal oscillator. The following IRQ modes are supported:
IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_HIGH and
IRQ_TYPE_LEVEL_LOW. The driver should detect and configure the hardware
for the desired interrupt type.
- vdd-supply : supply regulator for the main power voltage.
- vlogic-supply : supply regulator for the signal voltage.
- mount-matrix : see iio/mount-matrix.txt
Optional subnodes:
- The MPU-3050 will pass through and forward the I2C signals from the
incoming I2C bus, alternatively drive traffic to a slave device (usually
an accelerometer) on its own initiative. Therefore is supports a subnode
i2c gate node. For details see: i2c/i2c-gate.txt
Example:
mpu3050@68 {
compatible = "invensense,mpu3050";
reg = <0x68>;
interrupt-parent = <&foo>;
interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&bar>;
vlogic-supply = <&baz>;
/* External I2C interface */
i2c-gate {
#address-cells = <1>;
#size-cells = <0>;
fnord@18 {
compatible = "fnord";
reg = <0x18>;
interrupt-parent = <&foo>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
};
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/gyroscope/invensense,mpu3050.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Invensense MPU-3050 Gyroscope
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
const: invensense,mpu3050
reg:
maxItems: 1
vdd-supply: true
vlogic-supply: true
interrupts:
minItems: 1
description:
Interrupt mapping for the trigger interrupt from the internal oscillator.
mount-matrix: true
i2c-gate:
$ref: /schemas/i2c/i2c-controller.yaml
unevaluatedProperties: false
description: |
The MPU-3050 will pass through and forward the I2C signals from the
incoming I2C bus, alternatively drive traffic to a slave device (usually
an accelerometer) on its own initiative. Therefore is supports an
i2c-gate subnode.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
gyroscope@68 {
compatible = "invensense,mpu3050";
reg = <0x68>;
interrupt-parent = <&foo>;
interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&bar>;
vlogic-supply = <&baz>;
i2c-gate {
#address-cells = <1>;
#size-cells = <0>;
magnetometer@c {
compatible = "ak,ak8975";
reg = <0x0c>;
};
};
};
};
...
InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
http://www.invensense.com/mems/gyro/mpu6050.html
Required properties:
- compatible : should be one of
"invensense,mpu6000"
"invensense,mpu6050"
"invensense,mpu6500"
"invensense,mpu6515"
"invensense,mpu9150"
"invensense,mpu9250"
"invensense,mpu9255"
"invensense,icm20608"
"invensense,icm20609"
"invensense,icm20689"
"invensense,icm20602"
"invensense,icm20690"
"invensense,iam20680"
- reg : the I2C address of the sensor
- interrupts: interrupt mapping for IRQ. It should be configured with flags
IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
IRQ_TYPE_EDGE_FALLING.
Refer to interrupt-controller/interrupts.txt for generic interrupt client node
bindings.
Optional properties:
- vdd-supply: regulator phandle for VDD supply
- vddio-supply: regulator phandle for VDDIO supply
- mount-matrix: an optional 3x3 mounting rotation matrix
- i2c-gate node. These devices also support an auxiliary i2c bus. This is
simple enough to be described using the i2c-gate binding. See
i2c/i2c-gate.txt for more details.
Example:
mpu6050@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
interrupt-parent = <&gpio1>;
interrupts = <18 IRQ_TYPE_EDGE_RISING>;
mount-matrix = "-0.984807753012208", /* x0 */
"0", /* y0 */
"-0.173648177666930", /* z0 */
"0", /* x1 */
"-1", /* y1 */
"0", /* z1 */
"-0.173648177666930", /* x2 */
"0", /* y2 */
"0.984807753012208"; /* z2 */
};
mpu9250@68 {
compatible = "invensense,mpu9250";
reg = <0x68>;
interrupt-parent = <&gpio3>;
interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
i2c-gate {
#address-cells = <1>;
#size-cells = <0>;
ax8975@c {
compatible = "ak,ak8975";
reg = <0x0c>;
};
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/invensense,mpu6050.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
maintainers:
- Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
description: |
These devices support both I2C and SPI bus interfaces.
properties:
compatible:
enum:
- invensense,iam20680
- invensense,icm20608
- invensense,icm20609
- invensense,icm20689
- invensense,icm20602
- invensense,icm20690
- invensense,mpu6000
- invensense,mpu6050
- invensense,mpu6500
- invensense,mpu6515
- invensense,mpu6880
- invensense,mpu9150
- invensense,mpu9250
- invensense,mpu9255
reg:
maxItems: 1
interrupts:
maxItems: 1
spi-max-frequency: true
vdd-supply: true
vddio-supply: true
mount-matrix: true
i2c-gate:
$ref: /schemas/i2c/i2c-controller.yaml
unevaluatedProperties: false
description: |
These devices also support an auxiliary i2c bus via an i2c-gate.
allOf:
- if:
not:
properties:
compatible:
contains:
enum:
- invensense,mpu9150
- invensense,mpu9250
- invensense,mpu9255
then:
properties:
i2c-gate: false
additionalProperties: false
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
imu@68 {
compatible = "invensense,mpu9250";
reg = <0x68>;
interrupt-parent = <&gpio3>;
interrupts = <21 IRQ_TYPE_LEVEL_HIGH>;
mount-matrix = "-0.984807753012208", /* x0 */
"0", /* y0 */
"-0.173648177666930", /* z0 */
"0", /* x1 */
"-1", /* y1 */
"0", /* z1 */
"-0.173648177666930", /* x2 */
"0", /* y2 */
"0.984807753012208"; /* z2 */
i2c-gate {
#address-cells = <1>;
#size-cells = <0>;
magnetometer@c {
compatible = "ak,ak8975";
reg = <0x0c>;
};
};
};
};
...
...@@ -30,6 +30,9 @@ properties: ...@@ -30,6 +30,9 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
vdd-supply: true
vddio-supply: true
interrupts: interrupts:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/magnetometer/yamaha,yas530.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Yamaha YAS530 family of magnetometer sensors
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description:
The Yamaha YAS530 magnetometers is a line of 3-axis magnetometers
first introduced by Yamaha in 2009 with the YAS530. They are successors
of Yamaha's first magnetometer YAS529. Over the years this magnetometer
has been miniaturized and appeared in a number of different variants.
properties:
$nodename:
pattern: '^magnetometer@[0-9a-f]+$'
compatible:
items:
- enum:
- yamaha,yas530
- yamaha,yas532
- yamaha,yas533
- yamaha,yas535
- yamaha,yas536
- yamaha,yas537
- yamaha,yas539
reg:
maxItems: 1
reset-gpios:
maxItems: 1
description: The YAS530 sensor has a RSTN pin used to reset
the logic inside the sensor. This GPIO line should connect
to that pin and be marked as GPIO_ACTIVE_LOW.
interrupts:
maxItems: 1
description: Interrupt for INT pin for interrupt generation.
The polarity, whether the interrupt is active on the rising
or the falling edge, is software-configurable in the hardware.
vdd-supply:
description: An optional regulator providing core power supply
on the VDD pin, typically 1.8 V or 3.0 V.
iovdd-supply:
description: An optional regulator providing I/O power supply
for the I2C interface on the IOVDD pin, typically 1.8 V.
mount-matrix:
description: An optional 3x3 mounting rotation matrix.
allOf:
- if:
not:
properties:
compatible:
items:
const: yamaha,yas530
then:
properties:
reset-gpios: false
- if:
properties:
compatible:
items:
const: yamaha,yas539
then:
properties:
interrupts: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
i2c-0 {
#address-cells = <1>;
#size-cells = <0>;
magnetometer@2e {
compatible = "yamaha,yas530";
reg = <0x2e>;
vdd-supply = <&ldo1_reg>;
iovdd-supply = <&ldo2_reg>;
reset-gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
interrupts = <&gpio6 13 IRQ_TYPE_EDGE_RISING>;
};
};
i2c-1 {
#address-cells = <1>;
#size-cells = <0>;
magnetometer@2e {
compatible = "yamaha,yas539";
reg = <0x2e>;
vdd-supply = <&ldo1_reg>;
};
};
...@@ -148,15 +148,13 @@ properties: ...@@ -148,15 +148,13 @@ properties:
- maxim,max31730 - maxim,max31730
# mCube 3-axis 8-bit digital accelerometer # mCube 3-axis 8-bit digital accelerometer
- mcube,mc3230 - mcube,mc3230
# MEMSIC magnetometer
- memsic,mmc35240
# MEMSIC 2-axis 8-bit digital accelerometer
- memsic,mxc6225
# Measurement Specialities I2C temperature and humidity sensor # Measurement Specialities I2C temperature and humidity sensor
- meas,htu21 - meas,htu21
# Measurement Specialities I2C pressure and temperature sensor # Measurement Specialities I2C pressure and temperature sensor
- meas,ms5637 - meas,ms5637
# Measurement Specialities I2C pressure and temperature sensor # Measurement Specialities I2C pressure and temperature sensor
- meas,ms5803
# Measurement Specialities I2C pressure and temperature sensor
- meas,ms5805 - meas,ms5805
# Measurement Specialities I2C pressure and temperature sensor # Measurement Specialities I2C pressure and temperature sensor
- meas,ms5837 - meas,ms5837
...@@ -166,6 +164,10 @@ properties: ...@@ -166,6 +164,10 @@ properties:
- meas,ms8607-temppressure - meas,ms8607-temppressure
# Measurement Specialties temperature sensor # Measurement Specialties temperature sensor
- meas,tsys01 - meas,tsys01
# MEMSIC magnetometer
- memsic,mmc35240
# MEMSIC 2-axis 8-bit digital accelerometer
- memsic,mxc6225
# Microchip differential I2C ADC, 1 Channel, 18 bit # Microchip differential I2C ADC, 1 Channel, 18 bit
- microchip,mcp3421 - microchip,mcp3421
# Microchip differential I2C ADC, 2 Channel, 18 bit # Microchip differential I2C ADC, 2 Channel, 18 bit
......
...@@ -1252,6 +1252,8 @@ patternProperties: ...@@ -1252,6 +1252,8 @@ patternProperties:
description: Shenzhen Xunlong Software CO.,Limited description: Shenzhen Xunlong Software CO.,Limited
"^xylon,.*": "^xylon,.*":
description: Xylon description: Xylon
"^yamaha,.*":
description: Yamaha Corporation
"^yes-optoelectronics,.*": "^yes-optoelectronics,.*":
description: Yes Optoelectronics Co.,Ltd. description: Yes Optoelectronics Co.,Ltd.
"^ylm,.*": "^ylm,.*":
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* Copyright (c) 2015, Intel Corporation. * Copyright (c) 2015, Intel Corporation.
*/ */
#include <linux/ctype.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#define HID_CUSTOM_TOTAL_ATTRS (HID_CUSTOM_MAX_CORE_ATTRS + 1) #define HID_CUSTOM_TOTAL_ATTRS (HID_CUSTOM_MAX_CORE_ATTRS + 1)
#define HID_CUSTOM_FIFO_SIZE 4096 #define HID_CUSTOM_FIFO_SIZE 4096
#define HID_CUSTOM_MAX_FEATURE_BYTES 64 #define HID_CUSTOM_MAX_FEATURE_BYTES 64
#define HID_SENSOR_USAGE_LENGTH (4 + 1)
struct hid_sensor_custom_field { struct hid_sensor_custom_field {
int report_id; int report_id;
...@@ -50,6 +52,7 @@ struct hid_sensor_custom { ...@@ -50,6 +52,7 @@ struct hid_sensor_custom {
struct kfifo data_fifo; struct kfifo data_fifo;
unsigned long misc_opened; unsigned long misc_opened;
wait_queue_head_t wait; wait_queue_head_t wait;
struct platform_device *custom_pdev;
}; };
/* Header for each sample to user space via dev interface */ /* Header for each sample to user space via dev interface */
...@@ -746,11 +749,130 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom ...@@ -746,11 +749,130 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom
} }
/* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */
static const char *const known_sensor_luid[] = { "020B000000000000" };
static int get_luid_table_index(unsigned char *usage_str)
{
int i;
for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) {
if (!strncmp(usage_str, known_sensor_luid[i],
strlen(known_sensor_luid[i])))
return i;
}
return -ENODEV;
}
static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev)
{
struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 };
struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 };
int report_size;
int ret;
static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES];
static char buf[HID_CUSTOM_MAX_FEATURE_BYTES];
int i;
memset(w_buf, 0, sizeof(w_buf));
memset(buf, 0, sizeof(buf));
/* get manufacturer info */
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, hsdev->usage,
HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer);
if (ret < 0)
return ret;
report_size =
sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id,
sensor_manufacturer.index, sizeof(w_buf),
w_buf);
if (report_size <= 0) {
hid_err(hsdev->hdev,
"Failed to get sensor manufacturer info %d\n",
report_size);
return -ENODEV;
}
/* convert from wide char to char */
for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++)
buf[i] = (char)w_buf[i];
/* ensure it's ISH sensor */
if (strncmp(buf, "INTEL", strlen("INTEL")))
return -ENODEV;
memset(w_buf, 0, sizeof(w_buf));
memset(buf, 0, sizeof(buf));
/* get real usage id */
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, hsdev->usage,
HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info);
if (ret < 0)
return ret;
report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id,
sensor_luid_info.index, sizeof(w_buf),
w_buf);
if (report_size <= 0) {
hid_err(hsdev->hdev, "Failed to get real usage info %d\n",
report_size);
return -ENODEV;
}
/* convert from wide char to char */
for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++)
buf[i] = (char)w_buf[i];
if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) {
hid_err(hsdev->hdev,
"%s luid length not match %zu != (%zu + 5)\n", __func__,
strlen(buf), strlen(known_sensor_luid[0]));
return -ENODEV;
}
/* get table index with luid (not matching 'LUID: ' in luid) */
return get_luid_table_index(&buf[5]);
}
static struct platform_device *
hid_sensor_register_platform_device(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
int index)
{
char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 };
struct platform_device *custom_pdev;
const char *dev_name;
char *c;
/* copy real usage id */
memcpy(real_usage, known_sensor_luid[index], 4);
/* usage id are all lowcase */
for (c = real_usage; *c != '\0'; c++)
*c = tolower(*c);
/* HID-SENSOR-INT-REAL_USAGE_ID */
dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage);
if (!dev_name)
return ERR_PTR(-ENOMEM);
custom_pdev = platform_device_register_data(pdev->dev.parent, dev_name,
PLATFORM_DEVID_NONE, hsdev,
sizeof(*hsdev));
kfree(dev_name);
return custom_pdev;
}
static int hid_sensor_custom_probe(struct platform_device *pdev) static int hid_sensor_custom_probe(struct platform_device *pdev)
{ {
struct hid_sensor_custom *sensor_inst; struct hid_sensor_custom *sensor_inst;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
int ret; int ret;
int index;
sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
GFP_KERNEL); GFP_KERNEL);
...@@ -764,6 +886,22 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) ...@@ -764,6 +886,22 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
sensor_inst->pdev = pdev; sensor_inst->pdev = pdev;
mutex_init(&sensor_inst->mutex); mutex_init(&sensor_inst->mutex);
platform_set_drvdata(pdev, sensor_inst); platform_set_drvdata(pdev, sensor_inst);
index = get_known_custom_sensor_index(hsdev);
if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) {
sensor_inst->custom_pdev =
hid_sensor_register_platform_device(pdev, hsdev, index);
ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev);
if (ret) {
dev_err(&pdev->dev,
"register_platform_device failed\n");
return ret;
}
return 0;
}
ret = sensor_hub_register_callback(hsdev, hsdev->usage, ret = sensor_hub_register_callback(hsdev, hsdev->usage,
&sensor_inst->callbacks); &sensor_inst->callbacks);
if (ret < 0) { if (ret < 0) {
...@@ -802,6 +940,11 @@ static int hid_sensor_custom_remove(struct platform_device *pdev) ...@@ -802,6 +940,11 @@ static int hid_sensor_custom_remove(struct platform_device *pdev)
struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev); struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
if (sensor_inst->custom_pdev) {
platform_device_unregister(sensor_inst->custom_pdev);
return 0;
}
hid_sensor_custom_dev_if_remove(sensor_inst); hid_sensor_custom_dev_if_remove(sensor_inst);
hid_sensor_custom_remove_attributes(sensor_inst); hid_sensor_custom_remove_attributes(sensor_inst);
sysfs_remove_group(&sensor_inst->pdev->dev.kobj, sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
......
...@@ -23,6 +23,7 @@ enum accel_3d_channel { ...@@ -23,6 +23,7 @@ enum accel_3d_channel {
ACCEL_3D_CHANNEL_MAX, ACCEL_3D_CHANNEL_MAX,
}; };
#define CHANNEL_SCAN_INDEX_TIMESTAMP ACCEL_3D_CHANNEL_MAX
struct accel_3d_state { struct accel_3d_state {
struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes; struct hid_sensor_common common_attributes;
...@@ -75,7 +76,7 @@ static const struct iio_chan_spec accel_3d_channels[] = { ...@@ -75,7 +76,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
}, },
IIO_CHAN_SOFT_TIMESTAMP(3) IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
}; };
/* Channel definitions */ /* Channel definitions */
...@@ -110,7 +111,8 @@ static const struct iio_chan_spec gravity_channels[] = { ...@@ -110,7 +111,8 @@ static const struct iio_chan_spec gravity_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
} },
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP),
}; };
/* Adjust channel real bits based on report descriptor */ /* Adjust channel real bits based on report descriptor */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h> #include <linux/iio/buffer.h>
...@@ -133,6 +134,7 @@ enum kx_acpi_type { ...@@ -133,6 +134,7 @@ enum kx_acpi_type {
}; };
struct kxcjk1013_data { struct kxcjk1013_data {
struct regulator_bulk_data regulators[2];
struct i2c_client *client; struct i2c_client *client;
struct iio_trigger *dready_trig; struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig; struct iio_trigger *motion_trig;
...@@ -1300,6 +1302,13 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev, ...@@ -1300,6 +1302,13 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
return dev_name(dev); return dev_name(dev);
} }
static void kxcjk1013_disable_regulators(void *d)
{
struct kxcjk1013_data *data = d;
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
}
static int kxcjk1013_probe(struct i2c_client *client, static int kxcjk1013_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -1330,6 +1339,29 @@ static int kxcjk1013_probe(struct i2c_client *client, ...@@ -1330,6 +1339,29 @@ static int kxcjk1013_probe(struct i2c_client *client,
return ret; return ret;
} }
data->regulators[0].supply = "vdd";
data->regulators[1].supply = "vddio";
ret = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators),
data->regulators);
if (ret)
return dev_err_probe(&client->dev, ret, "Failed to get regulators\n");
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret)
return ret;
ret = devm_add_action_or_reset(&client->dev, kxcjk1013_disable_regulators, data);
if (ret)
return ret;
/*
* A typical delay of 10ms is required for powering up
* according to the data sheets of supported chips.
* Hence double that to play safe.
*/
msleep(20);
if (id) { if (id) {
data->chipset = (enum kx_chipset)(id->driver_data); data->chipset = (enum kx_chipset)(id->driver_data);
name = id->name; name = id->name;
......
...@@ -1228,8 +1228,15 @@ config XILINX_XADC ...@@ -1228,8 +1228,15 @@ config XILINX_XADC
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
help help
Say yes here to have support for the Xilinx XADC. The driver does support Say yes here to have support for the Xilinx 7 Series XADC or
both the ZYNQ interface to the XADC as well as the AXI-XADC interface. UltraScale/UltraScale+ System Management Wizard.
For the 7 Series the driver does support both the ZYNQ interface
to the XADC as well as the AXI-XADC interface.
The driver also support the Xilinx System Management Wizard IP core
that can be used to access the System Monitor ADC on the Xilinx
UltraScale and UltraScale+ FPGAs.
The driver can also be build as a module. If so, the module will be called The driver can also be build as a module. If so, the module will be called
xilinx-xadc. xilinx-xadc.
......
...@@ -1108,10 +1108,14 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) ...@@ -1108,10 +1108,14 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
return gpadc->irq_sw; return gpadc->irq_sw;
} }
gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END"); if (is_ab8500(gpadc->ab8500)) {
if (gpadc->irq_hw < 0) { gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
dev_err(dev, "failed to get platform hw_conv_end irq\n"); if (gpadc->irq_hw < 0) {
return gpadc->irq_hw; dev_err(dev, "failed to get platform hw_conv_end irq\n");
return gpadc->irq_hw;
}
} else {
gpadc->irq_hw = 0;
} }
/* Initialize completion used to notify completion of conversion */ /* Initialize completion used to notify completion of conversion */
...@@ -1128,14 +1132,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) ...@@ -1128,14 +1132,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
return ret; return ret;
} }
ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL, if (gpadc->irq_hw) {
ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL,
"ab8500-gpadc-hw", gpadc); ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
if (ret < 0) { "ab8500-gpadc-hw", gpadc);
dev_err(dev, if (ret < 0) {
"Failed to request hw conversion irq: %d\n", dev_err(dev,
gpadc->irq_hw); "Failed to request hw conversion irq: %d\n",
return ret; gpadc->irq_hw);
return ret;
}
} }
/* The VTVout LDO used to power the AB8500 GPADC */ /* The VTVout LDO used to power the AB8500 GPADC */
......
...@@ -67,6 +67,7 @@ enum ad7476_supported_device_ids { ...@@ -67,6 +67,7 @@ enum ad7476_supported_device_ids {
ID_ADS7866, ID_ADS7866,
ID_ADS7867, ID_ADS7867,
ID_ADS7868, ID_ADS7868,
ID_LTC2314_14,
}; };
static void ad7091_convst(struct ad7476_state *st) static void ad7091_convst(struct ad7476_state *st)
...@@ -250,6 +251,10 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { ...@@ -250,6 +251,10 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = ADS786X_CHAN(8), .channel[0] = ADS786X_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
}, },
[ID_LTC2314_14] = {
.channel[0] = AD7940_CHAN(14),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
}; };
static const struct iio_info ad7476_info = { static const struct iio_info ad7476_info = {
...@@ -365,6 +370,7 @@ static const struct spi_device_id ad7476_id[] = { ...@@ -365,6 +370,7 @@ static const struct spi_device_id ad7476_id[] = {
{"ads7866", ID_ADS7866}, {"ads7866", ID_ADS7866},
{"ads7867", ID_ADS7867}, {"ads7867", ID_ADS7867},
{"ads7868", ID_ADS7868}, {"ads7868", ID_ADS7868},
{"ltc2314-14", ID_LTC2314_14},
{} {}
}; };
MODULE_DEVICE_TABLE(spi, ad7476_id); MODULE_DEVICE_TABLE(spi, ad7476_id);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* Author: Linus Walleij <linus.walleij@linaro.org> * Author: Linus Walleij <linus.walleij@linaro.org>
*/ */
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -21,8 +22,6 @@ ...@@ -21,8 +22,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include "qcom-vadc-common.h"
/* /*
* Definitions for the "user processor" registers lifted from the v3.4 * Definitions for the "user processor" registers lifted from the v3.4
* Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC: * Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC:
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -14,12 +15,12 @@ ...@@ -14,12 +15,12 @@
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <dt-bindings/iio/qcom,spmi-vadc.h> #include <dt-bindings/iio/qcom,spmi-vadc.h>
#include "qcom-vadc-common.h"
#define ADC5_USR_REVISION1 0x0 #define ADC5_USR_REVISION1 0x0
#define ADC5_USR_STATUS1 0x8 #define ADC5_USR_STATUS1 0x8
...@@ -154,18 +155,6 @@ struct adc5_chip { ...@@ -154,18 +155,6 @@ struct adc5_chip {
const struct adc5_data *data; const struct adc5_data *data;
}; };
static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
{.num = 1, .den = 1},
{.num = 1, .den = 3},
{.num = 1, .den = 4},
{.num = 1, .den = 6},
{.num = 1, .den = 20},
{.num = 1, .den = 8},
{.num = 10, .den = 81},
{.num = 1, .den = 10},
{.num = 1, .den = 16}
};
static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len) static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len)
{ {
return regmap_bulk_read(adc->regmap, adc->base + offset, data, len); return regmap_bulk_read(adc->regmap, adc->base + offset, data, len);
...@@ -181,55 +170,6 @@ static int adc5_masked_write(struct adc5_chip *adc, u16 offset, u8 mask, u8 val) ...@@ -181,55 +170,6 @@ static int adc5_masked_write(struct adc5_chip *adc, u16 offset, u8 mask, u8 val)
return regmap_update_bits(adc->regmap, adc->base + offset, mask, val); return regmap_update_bits(adc->regmap, adc->base + offset, mask, val);
} }
static int adc5_prescaling_from_dt(u32 num, u32 den)
{
unsigned int pre;
for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++)
if (adc5_prescale_ratios[pre].num == num &&
adc5_prescale_ratios[pre].den == den)
break;
if (pre == ARRAY_SIZE(adc5_prescale_ratios))
return -EINVAL;
return pre;
}
static int adc5_hw_settle_time_from_dt(u32 value,
const unsigned int *hw_settle)
{
unsigned int i;
for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) {
if (value == hw_settle[i])
return i;
}
return -EINVAL;
}
static int adc5_avg_samples_from_dt(u32 value)
{
if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX)
return -EINVAL;
return __ffs(value);
}
static int adc5_decimation_from_dt(u32 value,
const unsigned int *decimation)
{
unsigned int i;
for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) {
if (value == decimation[i])
return i;
}
return -EINVAL;
}
static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data) static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data)
{ {
int ret; int ret;
...@@ -511,7 +451,7 @@ static int adc_read_raw_common(struct iio_dev *indio_dev, ...@@ -511,7 +451,7 @@ static int adc_read_raw_common(struct iio_dev *indio_dev,
return ret; return ret;
ret = qcom_adc5_hw_scale(prop->scale_fn_type, ret = qcom_adc5_hw_scale(prop->scale_fn_type,
&adc5_prescale_ratios[prop->prescale], prop->prescale,
adc->data, adc->data,
adc_code_volt, val); adc_code_volt, val);
if (ret) if (ret)
...@@ -717,7 +657,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ...@@ -717,7 +657,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
ret = of_property_read_u32(node, "qcom,decimation", &value); ret = of_property_read_u32(node, "qcom,decimation", &value);
if (!ret) { if (!ret) {
ret = adc5_decimation_from_dt(value, data->decimation); ret = qcom_adc5_decimation_from_dt(value, data->decimation);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%02x invalid decimation %d\n", dev_err(dev, "%02x invalid decimation %d\n",
chan, value); chan, value);
...@@ -730,7 +670,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ...@@ -730,7 +670,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2); ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
if (!ret) { if (!ret) {
ret = adc5_prescaling_from_dt(varr[0], varr[1]); ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%02x invalid pre-scaling <%d %d>\n", dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
chan, varr[0], varr[1]); chan, varr[0], varr[1]);
...@@ -759,11 +699,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ...@@ -759,11 +699,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
if ((dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR && if ((dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR &&
dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR) || dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR) ||
adc->data->info == &adc7_info) adc->data->info == &adc7_info)
ret = adc5_hw_settle_time_from_dt(value, ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_2);
data->hw_settle_2);
else else
ret = adc5_hw_settle_time_from_dt(value, ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1);
data->hw_settle_1);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%02x invalid hw-settle-time %d us\n", dev_err(dev, "%02x invalid hw-settle-time %d us\n",
...@@ -777,7 +715,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, ...@@ -777,7 +715,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
ret = of_property_read_u32(node, "qcom,avg-samples", &value); ret = of_property_read_u32(node, "qcom,avg-samples", &value);
if (!ret) { if (!ret) {
ret = adc5_avg_samples_from_dt(value); ret = qcom_adc5_avg_samples_from_dt(value);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%02x invalid avg-samples %d\n", dev_err(dev, "%02x invalid avg-samples %d\n",
chan, value); chan, value);
...@@ -870,8 +808,6 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node) ...@@ -870,8 +808,6 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
struct adc5_channel_prop prop, *chan_props; struct adc5_channel_prop prop, *chan_props;
struct device_node *child; struct device_node *child;
unsigned int index = 0; unsigned int index = 0;
const struct of_device_id *id;
const struct adc5_data *data;
int ret; int ret;
adc->nchannels = of_get_available_child_count(node); adc->nchannels = of_get_available_child_count(node);
...@@ -890,24 +826,21 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node) ...@@ -890,24 +826,21 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
chan_props = adc->chan_props; chan_props = adc->chan_props;
iio_chan = adc->iio_chans; iio_chan = adc->iio_chans;
id = of_match_node(adc5_match_table, node); adc->data = of_device_get_match_data(adc->dev);
if (id) if (!adc->data)
data = id->data; adc->data = &adc5_data_pmic;
else
data = &adc5_data_pmic;
adc->data = data;
for_each_available_child_of_node(node, child) { for_each_available_child_of_node(node, child) {
ret = adc5_get_dt_channel_data(adc, &prop, child, data); ret = adc5_get_dt_channel_data(adc, &prop, child, adc->data);
if (ret) { if (ret) {
of_node_put(child); of_node_put(child);
return ret; return ret;
} }
prop.scale_fn_type = prop.scale_fn_type =
data->adc_chans[prop.channel].scale_fn_type; adc->data->adc_chans[prop.channel].scale_fn_type;
*chan_props = prop; *chan_props = prop;
adc_chan = &data->adc_chans[prop.channel]; adc_chan = &adc->data->adc_chans[prop.channel];
iio_chan->channel = prop.channel; iio_chan->channel = prop.channel;
iio_chan->datasheet_name = prop.datasheet_name; iio_chan->datasheet_name = prop.datasheet_name;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -20,8 +21,6 @@ ...@@ -20,8 +21,6 @@
#include <dt-bindings/iio/qcom,spmi-vadc.h> #include <dt-bindings/iio/qcom,spmi-vadc.h>
#include "qcom-vadc-common.h"
/* VADC register and bit definitions */ /* VADC register and bit definitions */
#define VADC_REVISION2 0x1 #define VADC_REVISION2 0x1
#define VADC_REVISION2_SUPPORTED_VADC 1 #define VADC_REVISION2_SUPPORTED_VADC 1
......
...@@ -2,50 +2,61 @@ ...@@ -2,50 +2,61 @@
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/fixp-arith.h>
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/units.h> #include <linux/units.h>
#include "qcom-vadc-common.h" /**
* struct vadc_map_pt - Map the graph representation for ADC channel
* @x: Represent the ADC digitized code.
* @y: Represent the physical data which can be temperature, voltage,
* resistance.
*/
struct vadc_map_pt {
s32 x;
s32 y;
};
/* Voltage to temperature */ /* Voltage to temperature */
static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = { static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
{1758, -40}, {1758, -40000 },
{1742, -35}, {1742, -35000 },
{1719, -30}, {1719, -30000 },
{1691, -25}, {1691, -25000 },
{1654, -20}, {1654, -20000 },
{1608, -15}, {1608, -15000 },
{1551, -10}, {1551, -10000 },
{1483, -5}, {1483, -5000 },
{1404, 0}, {1404, 0 },
{1315, 5}, {1315, 5000 },
{1218, 10}, {1218, 10000 },
{1114, 15}, {1114, 15000 },
{1007, 20}, {1007, 20000 },
{900, 25}, {900, 25000 },
{795, 30}, {795, 30000 },
{696, 35}, {696, 35000 },
{605, 40}, {605, 40000 },
{522, 45}, {522, 45000 },
{448, 50}, {448, 50000 },
{383, 55}, {383, 55000 },
{327, 60}, {327, 60000 },
{278, 65}, {278, 65000 },
{237, 70}, {237, 70000 },
{202, 75}, {202, 75000 },
{172, 80}, {172, 80000 },
{146, 85}, {146, 85000 },
{125, 90}, {125, 90000 },
{107, 95}, {107, 95000 },
{92, 100}, {92, 100000 },
{79, 105}, {79, 105000 },
{68, 110}, {68, 110000 },
{59, 115}, {59, 115000 },
{51, 120}, {51, 120000 },
{44, 125} {44, 125000 }
}; };
/* /*
...@@ -90,18 +101,18 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = { ...@@ -90,18 +101,18 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
}; };
static const struct vadc_map_pt adcmap7_die_temp[] = { static const struct vadc_map_pt adcmap7_die_temp[] = {
{ 433700, 1967}, { 857300, 160000 },
{ 473100, 1964}, { 820100, 140000 },
{ 512400, 1957}, { 782500, 120000 },
{ 551500, 1949}, { 744600, 100000 },
{ 590500, 1940}, { 706400, 80000 },
{ 629300, 1930}, { 667900, 60000 },
{ 667900, 1921}, { 629300, 40000 },
{ 706400, 1910}, { 590500, 20000 },
{ 744600, 1896}, { 551500, 0 },
{ 782500, 1878}, { 512400, -20000 },
{ 820100, 1859}, { 473100, -40000 },
{ 857300, 0}, { 433700, -60000 },
}; };
/* /*
...@@ -278,6 +289,18 @@ static const struct vadc_map_pt adcmap7_100k[] = { ...@@ -278,6 +289,18 @@ static const struct vadc_map_pt adcmap7_100k[] = {
{ 2420, 130048 } { 2420, 130048 }
}; };
static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
{.num = 1, .den = 1},
{.num = 1, .den = 3},
{.num = 1, .den = 4},
{.num = 1, .den = 6},
{.num = 1, .den = 20},
{.num = 1, .den = 8},
{.num = 10, .den = 81},
{.num = 1, .den = 10},
{.num = 1, .den = 16}
};
static int qcom_vadc_scale_hw_calib_volt( static int qcom_vadc_scale_hw_calib_volt(
const struct vadc_prescale_ratio *prescale, const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data, const struct adc5_data *data,
...@@ -323,43 +346,23 @@ static struct qcom_adc5_scale_type scale_adc5_fn[] = { ...@@ -323,43 +346,23 @@ static struct qcom_adc5_scale_type scale_adc5_fn[] = {
static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts, static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
u32 tablesize, s32 input, int *output) u32 tablesize, s32 input, int *output)
{ {
bool descending = 1;
u32 i = 0; u32 i = 0;
if (!pts) if (!pts)
return -EINVAL; return -EINVAL;
/* Check if table is descending or ascending */ while (i < tablesize && pts[i].x > input)
if (tablesize > 1) {
if (pts[0].x < pts[1].x)
descending = 0;
}
while (i < tablesize) {
if ((descending) && (pts[i].x < input)) {
/* table entry is less than measured*/
/* value and table is descending, stop */
break;
} else if ((!descending) &&
(pts[i].x > input)) {
/* table entry is greater than measured*/
/*value and table is ascending, stop */
break;
}
i++; i++;
}
if (i == 0) { if (i == 0) {
*output = pts[0].y; *output = pts[0].y;
} else if (i == tablesize) { } else if (i == tablesize) {
*output = pts[tablesize - 1].y; *output = pts[tablesize - 1].y;
} else { } else {
/* result is between search_index and search_index-1 */
/* interpolate linearly */ /* interpolate linearly */
*output = (((s32)((pts[i].y - pts[i - 1].y) * *output = fixp_linear_interpolate(pts[i - 1].x, pts[i - 1].y,
(input - pts[i - 1].x)) / pts[i].x, pts[i].y,
(pts[i].x - pts[i - 1].x)) + input);
pts[i - 1].y);
} }
return 0; return 0;
...@@ -415,8 +418,6 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph, ...@@ -415,8 +418,6 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
if (ret) if (ret)
return ret; return ret;
*result_mdec *= 1000;
return 0; return 0;
} }
...@@ -563,33 +564,13 @@ static int qcom_vadc7_scale_hw_calib_die_temp( ...@@ -563,33 +564,13 @@ static int qcom_vadc7_scale_hw_calib_die_temp(
u16 adc_code, int *result_mdec) u16 adc_code, int *result_mdec)
{ {
int voltage, vtemp0, temp, i; int voltage;
voltage = qcom_vadc_scale_code_voltage_factor(adc_code, voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
prescale, data, 1); prescale, data, 1);
if (adcmap7_die_temp[0].x > voltage) { return qcom_vadc_map_voltage_temp(adcmap7_die_temp, ARRAY_SIZE(adcmap7_die_temp),
*result_mdec = DIE_TEMP_ADC7_SCALE_1; voltage, result_mdec);
return 0;
}
if (adcmap7_die_temp[ARRAY_SIZE(adcmap7_die_temp) - 1].x <= voltage) {
*result_mdec = DIE_TEMP_ADC7_MAX;
return 0;
}
for (i = 0; i < ARRAY_SIZE(adcmap7_die_temp); i++)
if (adcmap7_die_temp[i].x > voltage)
break;
vtemp0 = adcmap7_die_temp[i - 1].x;
voltage = voltage - vtemp0;
temp = div64_s64(voltage * DIE_TEMP_ADC7_SCALE_FACTOR,
adcmap7_die_temp[i - 1].y);
temp += DIE_TEMP_ADC7_SCALE_1 + (DIE_TEMP_ADC7_SCALE_2 * (i - 1));
*result_mdec = temp;
return 0;
} }
static int qcom_vadc_scale_hw_smb_temp( static int qcom_vadc_scale_hw_smb_temp(
...@@ -647,10 +628,12 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, ...@@ -647,10 +628,12 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
EXPORT_SYMBOL(qcom_vadc_scale); EXPORT_SYMBOL(qcom_vadc_scale);
int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
const struct vadc_prescale_ratio *prescale, unsigned int prescale_ratio,
const struct adc5_data *data, const struct adc5_data *data,
u16 adc_code, int *result) u16 adc_code, int *result)
{ {
const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio];
if (!(scaletype >= SCALE_HW_CALIB_DEFAULT && if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
scaletype < SCALE_HW_CALIB_INVALID)) { scaletype < SCALE_HW_CALIB_INVALID)) {
pr_err("Invalid scale type %d\n", scaletype); pr_err("Invalid scale type %d\n", scaletype);
...@@ -662,6 +645,58 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype, ...@@ -662,6 +645,58 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
} }
EXPORT_SYMBOL(qcom_adc5_hw_scale); EXPORT_SYMBOL(qcom_adc5_hw_scale);
int qcom_adc5_prescaling_from_dt(u32 num, u32 den)
{
unsigned int pre;
for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++)
if (adc5_prescale_ratios[pre].num == num &&
adc5_prescale_ratios[pre].den == den)
break;
if (pre == ARRAY_SIZE(adc5_prescale_ratios))
return -EINVAL;
return pre;
}
EXPORT_SYMBOL(qcom_adc5_prescaling_from_dt);
int qcom_adc5_hw_settle_time_from_dt(u32 value,
const unsigned int *hw_settle)
{
unsigned int i;
for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) {
if (value == hw_settle[i])
return i;
}
return -EINVAL;
}
EXPORT_SYMBOL(qcom_adc5_hw_settle_time_from_dt);
int qcom_adc5_avg_samples_from_dt(u32 value)
{
if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX)
return -EINVAL;
return __ffs(value);
}
EXPORT_SYMBOL(qcom_adc5_avg_samples_from_dt);
int qcom_adc5_decimation_from_dt(u32 value, const unsigned int *decimation)
{
unsigned int i;
for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) {
if (value == decimation[i])
return i;
}
return -EINVAL;
}
EXPORT_SYMBOL(qcom_adc5_decimation_from_dt);
int qcom_vadc_decimation_from_dt(u32 value) int qcom_vadc_decimation_from_dt(u32 value)
{ {
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN || if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
......
...@@ -307,7 +307,7 @@ static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel, ...@@ -307,7 +307,7 @@ static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel,
sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator); sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator);
return (volt * denominator + numerator / 2) / numerator; return DIV_ROUND_CLOSEST(volt * denominator, numerator);
} }
static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data, static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data,
......
...@@ -535,20 +535,16 @@ static int stm32_adc_core_hw_start(struct device *dev) ...@@ -535,20 +535,16 @@ static int stm32_adc_core_hw_start(struct device *dev)
goto err_switches_dis; goto err_switches_dis;
} }
if (priv->bclk) { ret = clk_prepare_enable(priv->bclk);
ret = clk_prepare_enable(priv->bclk); if (ret < 0) {
if (ret < 0) { dev_err(dev, "bus clk enable failed\n");
dev_err(dev, "bus clk enable failed\n"); goto err_regulator_disable;
goto err_regulator_disable;
}
} }
if (priv->aclk) { ret = clk_prepare_enable(priv->aclk);
ret = clk_prepare_enable(priv->aclk); if (ret < 0) {
if (ret < 0) { dev_err(dev, "adc clk enable failed\n");
dev_err(dev, "adc clk enable failed\n"); goto err_bclk_disable;
goto err_bclk_disable;
}
} }
writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr); writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr);
...@@ -556,8 +552,7 @@ static int stm32_adc_core_hw_start(struct device *dev) ...@@ -556,8 +552,7 @@ static int stm32_adc_core_hw_start(struct device *dev)
return 0; return 0;
err_bclk_disable: err_bclk_disable:
if (priv->bclk) clk_disable_unprepare(priv->bclk);
clk_disable_unprepare(priv->bclk);
err_regulator_disable: err_regulator_disable:
regulator_disable(priv->vref); regulator_disable(priv->vref);
err_switches_dis: err_switches_dis:
...@@ -575,10 +570,8 @@ static void stm32_adc_core_hw_stop(struct device *dev) ...@@ -575,10 +570,8 @@ static void stm32_adc_core_hw_stop(struct device *dev)
/* Backup CCR that may be lost (depends on power state to achieve) */ /* Backup CCR that may be lost (depends on power state to achieve) */
priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr); priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr);
if (priv->aclk) clk_disable_unprepare(priv->aclk);
clk_disable_unprepare(priv->aclk); clk_disable_unprepare(priv->bclk);
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref); regulator_disable(priv->vref);
stm32_adc_core_switches_supply_dis(priv); stm32_adc_core_switches_supply_dis(priv);
regulator_disable(priv->vdda); regulator_disable(priv->vdda);
......
...@@ -546,8 +546,7 @@ static int stm32_adc_hw_stop(struct device *dev) ...@@ -546,8 +546,7 @@ static int stm32_adc_hw_stop(struct device *dev)
if (adc->cfg->unprepare) if (adc->cfg->unprepare)
adc->cfg->unprepare(indio_dev); adc->cfg->unprepare(indio_dev);
if (adc->clk) clk_disable_unprepare(adc->clk);
clk_disable_unprepare(adc->clk);
return 0; return 0;
} }
...@@ -558,11 +557,9 @@ static int stm32_adc_hw_start(struct device *dev) ...@@ -558,11 +557,9 @@ static int stm32_adc_hw_start(struct device *dev)
struct stm32_adc *adc = iio_priv(indio_dev); struct stm32_adc *adc = iio_priv(indio_dev);
int ret; int ret;
if (adc->clk) { ret = clk_prepare_enable(adc->clk);
ret = clk_prepare_enable(adc->clk); if (ret)
if (ret) return ret;
return ret;
}
stm32_adc_set_res(adc); stm32_adc_set_res(adc);
...@@ -575,8 +572,7 @@ static int stm32_adc_hw_start(struct device *dev) ...@@ -575,8 +572,7 @@ static int stm32_adc_hw_start(struct device *dev)
return 0; return 0;
err_clk_dis: err_clk_dis:
if (adc->clk) clk_disable_unprepare(adc->clk);
clk_disable_unprepare(adc->clk);
return ret; return ret;
} }
......
...@@ -117,8 +117,7 @@ static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) ...@@ -117,8 +117,7 @@ static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm)
{ {
struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm);
if (priv->aclk) clk_disable_unprepare(priv->aclk);
clk_disable_unprepare(priv->aclk);
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
} }
......
This diff is collapsed.
...@@ -155,9 +155,6 @@ int xadc_write_event_config(struct iio_dev *indio_dev, ...@@ -155,9 +155,6 @@ int xadc_write_event_config(struct iio_dev *indio_dev,
return ret; return ret;
} }
/* Register value is msb aligned, the lower 4 bits are ignored */
#define XADC_THRESHOLD_VALUE_SHIFT 4
int xadc_read_event_value(struct iio_dev *indio_dev, int xadc_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, enum iio_event_type type, const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info, enum iio_event_direction dir, enum iio_event_info info,
...@@ -177,7 +174,8 @@ int xadc_read_event_value(struct iio_dev *indio_dev, ...@@ -177,7 +174,8 @@ int xadc_read_event_value(struct iio_dev *indio_dev,
return -EINVAL; return -EINVAL;
} }
*val >>= XADC_THRESHOLD_VALUE_SHIFT; /* MSB aligned */
*val >>= 16 - chan->scan_type.realbits;
return IIO_VAL_INT; return IIO_VAL_INT;
} }
...@@ -191,7 +189,8 @@ int xadc_write_event_value(struct iio_dev *indio_dev, ...@@ -191,7 +189,8 @@ int xadc_write_event_value(struct iio_dev *indio_dev,
struct xadc *xadc = iio_priv(indio_dev); struct xadc *xadc = iio_priv(indio_dev);
int ret = 0; int ret = 0;
val <<= XADC_THRESHOLD_VALUE_SHIFT; /* MSB aligned */
val <<= 16 - chan->scan_type.realbits;
if (val < 0 || val > 0xffff) if (val < 0 || val > 0xffff)
return -EINVAL; return -EINVAL;
......
...@@ -70,6 +70,11 @@ struct xadc { ...@@ -70,6 +70,11 @@ struct xadc {
int irq; int irq;
}; };
enum xadc_type {
XADC_TYPE_S7, /* Series 7 */
XADC_TYPE_US, /* UltraScale and UltraScale+ */
};
struct xadc_ops { struct xadc_ops {
int (*read)(struct xadc *xadc, unsigned int reg, uint16_t *val); int (*read)(struct xadc *xadc, unsigned int reg, uint16_t *val);
int (*write)(struct xadc *xadc, unsigned int reg, uint16_t val); int (*write)(struct xadc *xadc, unsigned int reg, uint16_t val);
...@@ -80,6 +85,7 @@ struct xadc_ops { ...@@ -80,6 +85,7 @@ struct xadc_ops {
irqreturn_t (*interrupt_handler)(int irq, void *devid); irqreturn_t (*interrupt_handler)(int irq, void *devid);
unsigned int flags; unsigned int flags;
enum xadc_type type;
}; };
static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg, static inline int _xadc_read_adc_reg(struct xadc *xadc, unsigned int reg,
......
...@@ -479,7 +479,7 @@ static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp) ...@@ -479,7 +479,7 @@ static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp)
var4 = (var3 / (calib->res_heat_range + 4)); var4 = (var3 / (calib->res_heat_range + 4));
var5 = 131 * calib->res_heat_val + 65536; var5 = 131 * calib->res_heat_val + 65536;
heatr_res_x100 = ((var4 / var5) - 250) * 34; heatr_res_x100 = ((var4 / var5) - 250) * 34;
heatr_res = (heatr_res_x100 + 50) / 100; heatr_res = DIV_ROUND_CLOSEST(heatr_res_x100, 100);
return heatr_res; return heatr_res;
} }
......
...@@ -282,7 +282,7 @@ static int pms7003_probe(struct serdev_device *serdev) ...@@ -282,7 +282,7 @@ static int pms7003_probe(struct serdev_device *serdev)
state->serdev = serdev; state->serdev = serdev;
indio_dev->info = &pms7003_info; indio_dev->info = &pms7003_info;
indio_dev->name = PMS7003_DRIVER_NAME; indio_dev->name = PMS7003_DRIVER_NAME;
indio_dev->channels = pms7003_channels, indio_dev->channels = pms7003_channels;
indio_dev->num_channels = ARRAY_SIZE(pms7003_channels); indio_dev->num_channels = ARRAY_SIZE(pms7003_channels);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = pms7003_scan_masks; indio_dev->available_scan_masks = pms7003_scan_masks;
......
...@@ -71,6 +71,8 @@ static struct { ...@@ -71,6 +71,8 @@ static struct {
{HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0}, {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0},
{HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0}, {HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0},
{HID_USAGE_SENSOR_HINGE, 0, 0, 17453293},
{HID_USAGE_SENSOR_HINGE, HID_USAGE_SENSOR_UNITS_DEGREES, 0, 17453293},
}; };
static void simple_div(int dividend, int divisor, int *whole, static void simple_div(int dividend, int divisor, int *whole,
......
...@@ -488,24 +488,20 @@ int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data, ...@@ -488,24 +488,20 @@ int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
EXPORT_SYMBOL(ms_sensors_ht_read_humidity); EXPORT_SYMBOL(ms_sensors_ht_read_humidity);
/** /**
* ms_sensors_tp_crc_valid() - CRC check function for * ms_sensors_tp_crc4() - Calculate PROM CRC for
* Temperature and pressure devices. * Temperature and pressure devices.
* This function is only used when reading PROM coefficients * This function is only used when reading PROM coefficients
* *
* @prom: pointer to PROM coefficients array * @prom: pointer to PROM coefficients array
* @len: length of PROM coefficients array
* *
* Return: True if CRC is ok. * Return: CRC.
*/ */
static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len) static u8 ms_sensors_tp_crc4(u16 *prom)
{ {
unsigned int cnt, n_bit; unsigned int cnt, n_bit;
u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12; u16 n_rem = 0x0000;
prom[len - 1] = 0;
prom[0] &= 0x0FFF; /* Clear the CRC computation part */
for (cnt = 0; cnt < len * 2; cnt++) { for (cnt = 0; cnt < MS_SENSORS_TP_PROM_WORDS_NB * 2; cnt++) {
if (cnt % 2 == 1) if (cnt % 2 == 1)
n_rem ^= prom[cnt >> 1] & 0x00FF; n_rem ^= prom[cnt >> 1] & 0x00FF;
else else
...@@ -518,10 +514,55 @@ static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len) ...@@ -518,10 +514,55 @@ static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
n_rem <<= 1; n_rem <<= 1;
} }
} }
n_rem >>= 12;
prom[0] = crc_read;
return n_rem == crc; return n_rem >> 12;
}
/**
* ms_sensors_tp_crc_valid_112() - CRC check function for
* Temperature and pressure devices for 112bit PROM.
* This function is only used when reading PROM coefficients
*
* @prom: pointer to PROM coefficients array
*
* Return: True if CRC is ok.
*/
static bool ms_sensors_tp_crc_valid_112(u16 *prom)
{
u16 w0 = prom[0], crc_read = (w0 & 0xF000) >> 12;
u8 crc;
prom[0] &= 0x0FFF; /* Clear the CRC computation part */
prom[MS_SENSORS_TP_PROM_WORDS_NB - 1] = 0;
crc = ms_sensors_tp_crc4(prom);
prom[0] = w0;
return crc == crc_read;
}
/**
* ms_sensors_tp_crc_valid_128() - CRC check function for
* Temperature and pressure devices for 128bit PROM.
* This function is only used when reading PROM coefficients
*
* @prom: pointer to PROM coefficients array
*
* Return: True if CRC is ok.
*/
static bool ms_sensors_tp_crc_valid_128(u16 *prom)
{
u16 w7 = prom[7], crc_read = w7 & 0x000F;
u8 crc;
prom[7] &= 0xFF00; /* Clear the CRC and LSB part */
crc = ms_sensors_tp_crc4(prom);
prom[7] = w7;
return crc == crc_read;
} }
/** /**
...@@ -536,8 +577,9 @@ static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len) ...@@ -536,8 +577,9 @@ static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data) int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
{ {
int i, ret; int i, ret;
bool valid;
for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) { for (i = 0; i < dev_data->hw->prom_len; i++) {
ret = ms_sensors_read_prom_word( ret = ms_sensors_read_prom_word(
dev_data->client, dev_data->client,
MS_SENSORS_TP_PROM_READ + (i << 1), MS_SENSORS_TP_PROM_READ + (i << 1),
...@@ -547,8 +589,12 @@ int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data) ...@@ -547,8 +589,12 @@ int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
return ret; return ret;
} }
if (!ms_sensors_tp_crc_valid(dev_data->prom, if (dev_data->hw->prom_len == 8)
MS_SENSORS_TP_PROM_WORDS_NB + 1)) { valid = ms_sensors_tp_crc_valid_128(dev_data->prom);
else
valid = ms_sensors_tp_crc_valid_112(dev_data->prom);
if (!valid) {
dev_err(&dev_data->client->dev, dev_err(&dev_data->client->dev,
"Calibration coefficients crc check error\n"); "Calibration coefficients crc check error\n");
return -ENODEV; return -ENODEV;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#define MS_SENSORS_TP_PROM_WORDS_NB 7 #define MS_SENSORS_TP_PROM_WORDS_NB 8
/** /**
* struct ms_ht_dev - Humidity/Temperature sensor device structure * struct ms_ht_dev - Humidity/Temperature sensor device structure
...@@ -25,6 +25,16 @@ struct ms_ht_dev { ...@@ -25,6 +25,16 @@ struct ms_ht_dev {
u8 res_index; u8 res_index;
}; };
/**
* struct ms_hw_data - Temperature/Pressure sensor hardware data
* @prom_len: number of words in the PROM
* @max_res_index: maximum sensor resolution index
*/
struct ms_tp_hw_data {
u8 prom_len;
u8 max_res_index;
};
/** /**
* struct ms_tp_dev - Temperature/Pressure sensor device structure * struct ms_tp_dev - Temperature/Pressure sensor device structure
* @client: i2c client * @client: i2c client
...@@ -36,7 +46,8 @@ struct ms_ht_dev { ...@@ -36,7 +46,8 @@ struct ms_ht_dev {
struct ms_tp_dev { struct ms_tp_dev {
struct i2c_client *client; struct i2c_client *client;
struct mutex lock; struct mutex lock;
u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1]; const struct ms_tp_hw_data *hw;
u16 prom[MS_SENSORS_TP_PROM_WORDS_NB];
u8 res_index; u8 res_index;
}; };
......
...@@ -189,6 +189,16 @@ config AD5764 ...@@ -189,6 +189,16 @@ config AD5764
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ad5764. module will be called ad5764.
config AD5766
tristate "Analog Devices AD5766/AD5767 DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5766, AD5767
Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5766.
config AD5770R config AD5770R
tristate "Analog Devices AD5770R IDAC driver" tristate "Analog Devices AD5770R IDAC driver"
depends on SPI_MASTER depends on SPI_MASTER
......
...@@ -19,6 +19,7 @@ obj-$(CONFIG_AD5755) += ad5755.o ...@@ -19,6 +19,7 @@ obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5755) += ad5758.o obj-$(CONFIG_AD5755) += ad5758.o
obj-$(CONFIG_AD5761) += ad5761.o obj-$(CONFIG_AD5761) += ad5761.o
obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5766) += ad5766.o
obj-$(CONFIG_AD5770R) += ad5770r.o obj-$(CONFIG_AD5770R) += ad5770r.o
obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD5686) += ad5686.o
......
This diff is collapsed.
...@@ -582,8 +582,7 @@ static int adf4350_probe(struct spi_device *spi) ...@@ -582,8 +582,7 @@ static int adf4350_probe(struct spi_device *spi)
if (!IS_ERR(st->reg)) if (!IS_ERR(st->reg))
regulator_disable(st->reg); regulator_disable(st->reg);
error_disable_clk: error_disable_clk:
if (clk) clk_disable_unprepare(clk);
clk_disable_unprepare(clk);
return ret; return ret;
} }
...@@ -599,8 +598,7 @@ static int adf4350_remove(struct spi_device *spi) ...@@ -599,8 +598,7 @@ static int adf4350_remove(struct spi_device *spi)
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
if (st->clk) clk_disable_unprepare(st->clk);
clk_disable_unprepare(st->clk);
if (!IS_ERR(reg)) if (!IS_ERR(reg))
regulator_disable(reg); regulator_disable(reg);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/iio/trigger_consumer.h> #include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "bmg160.h" #include "bmg160.h"
#define BMG160_IRQ_NAME "bmg160_event" #define BMG160_IRQ_NAME "bmg160_event"
...@@ -92,6 +93,7 @@ ...@@ -92,6 +93,7 @@
struct bmg160_data { struct bmg160_data {
struct regmap *regmap; struct regmap *regmap;
struct regulator_bulk_data regulators[2];
struct iio_trigger *dready_trig; struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig; struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation; struct iio_mount_matrix orientation;
...@@ -1061,6 +1063,13 @@ static const char *bmg160_match_acpi_device(struct device *dev) ...@@ -1061,6 +1063,13 @@ static const char *bmg160_match_acpi_device(struct device *dev)
return dev_name(dev); return dev_name(dev);
} }
static void bmg160_disable_regulators(void *d)
{
struct bmg160_data *data = d;
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
}
int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name) const char *name)
{ {
...@@ -1077,6 +1086,22 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq, ...@@ -1077,6 +1086,22 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->irq = irq; data->irq = irq;
data->regmap = regmap; data->regmap = regmap;
data->regulators[0].supply = "vdd";
data->regulators[1].supply = "vddio";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
data->regulators);
if (ret)
return dev_err_probe(dev, ret, "Failed to get regulators\n");
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, bmg160_disable_regulators, data);
if (ret)
return ret;
ret = iio_read_mount_matrix(dev, "mount-matrix", ret = iio_read_mount_matrix(dev, "mount-matrix",
&data->orientation); &data->orientation);
if (ret) if (ret)
......
...@@ -23,15 +23,20 @@ enum gyro_3d_channel { ...@@ -23,15 +23,20 @@ enum gyro_3d_channel {
GYRO_3D_CHANNEL_MAX, GYRO_3D_CHANNEL_MAX,
}; };
#define CHANNEL_SCAN_INDEX_TIMESTAMP GYRO_3D_CHANNEL_MAX
struct gyro_3d_state { struct gyro_3d_state {
struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes; struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX]; struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX];
u32 gyro_val[GYRO_3D_CHANNEL_MAX]; struct {
u32 gyro_val[GYRO_3D_CHANNEL_MAX];
u64 timestamp __aligned(8);
} scan;
int scale_pre_decml; int scale_pre_decml;
int scale_post_decml; int scale_post_decml;
int scale_precision; int scale_precision;
int value_offset; int value_offset;
s64 timestamp;
}; };
static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
...@@ -72,7 +77,8 @@ static const struct iio_chan_spec gyro_3d_channels[] = { ...@@ -72,7 +77,8 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
} },
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
}; };
/* Adjust channel real bits based on report descriptor */ /* Adjust channel real bits based on report descriptor */
...@@ -178,14 +184,6 @@ static const struct iio_info gyro_3d_info = { ...@@ -178,14 +184,6 @@ static const struct iio_info gyro_3d_info = {
.write_raw = &gyro_3d_write_raw, .write_raw = &gyro_3d_write_raw,
}; };
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
int len)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
iio_push_to_buffers(indio_dev, data);
}
/* Callback handler to send event after all samples are received and captured */ /* Callback handler to send event after all samples are received and captured */
static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id, unsigned usage_id,
...@@ -195,10 +193,15 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, ...@@ -195,10 +193,15 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
struct gyro_3d_state *gyro_state = iio_priv(indio_dev); struct gyro_3d_state *gyro_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n"); dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n");
if (atomic_read(&gyro_state->common_attributes.data_ready)) if (atomic_read(&gyro_state->common_attributes.data_ready)) {
hid_sensor_push_data(indio_dev, if (!gyro_state->timestamp)
gyro_state->gyro_val, gyro_state->timestamp = iio_get_time_ns(indio_dev);
sizeof(gyro_state->gyro_val));
iio_push_to_buffers_with_timestamp(indio_dev, &gyro_state->scan,
gyro_state->timestamp);
gyro_state->timestamp = 0;
}
return 0; return 0;
} }
...@@ -219,10 +222,15 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, ...@@ -219,10 +222,15 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS: case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS:
case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS: case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS; offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS;
gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] = gyro_state->scan.gyro_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data; *(u32 *)raw_data;
ret = 0; ret = 0;
break; break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
gyro_state->timestamp =
hid_sensor_convert_timestamp(&gyro_state->common_attributes,
*(s64 *)raw_data);
break;
default: default:
break; break;
} }
......
...@@ -16,8 +16,8 @@ config INV_MPU6050_I2C ...@@ -16,8 +16,8 @@ config INV_MPU6050_I2C
select REGMAP_I2C select REGMAP_I2C
help help
This driver supports the Invensense MPU6050/9150, This driver supports the Invensense MPU6050/9150,
MPU6500/6515/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690 and MPU6500/6515/6880/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690
IAM20680 motion tracking devices over I2C. and IAM20680 motion tracking devices over I2C.
This driver can be built as a module. The module will be called This driver can be built as a module. The module will be called
inv-mpu6050-i2c. inv-mpu6050-i2c.
...@@ -28,7 +28,7 @@ config INV_MPU6050_SPI ...@@ -28,7 +28,7 @@ config INV_MPU6050_SPI
select REGMAP_SPI select REGMAP_SPI
help help
This driver supports the Invensense MPU6000, This driver supports the Invensense MPU6000,
MPU6500/6515/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690 and MPU6500/6515/6880/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690
IAM20680 motion tracking devices over SPI. and IAM20680 motion tracking devices over SPI.
This driver can be built as a module. The module will be called This driver can be built as a module. The module will be called
inv-mpu6050-spi. inv-mpu6050-spi.
...@@ -160,6 +160,14 @@ static const struct inv_mpu6050_hw hw_info[] = { ...@@ -160,6 +160,14 @@ static const struct inv_mpu6050_hw hw_info[] = {
.fifo_size = 512, .fifo_size = 512,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
}, },
{
.whoami = INV_MPU6880_WHOAMI_VALUE,
.name = "MPU6880",
.reg = &reg_set_6500,
.config = &chip_config_6500,
.fifo_size = 4096,
.temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
},
{ {
.whoami = INV_MPU6000_WHOAMI_VALUE, .whoami = INV_MPU6000_WHOAMI_VALUE,
.name = "MPU6000", .name = "MPU6000",
...@@ -1323,6 +1331,7 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) ...@@ -1323,6 +1331,7 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
case INV_MPU6000: case INV_MPU6000:
case INV_MPU6500: case INV_MPU6500:
case INV_MPU6515: case INV_MPU6515:
case INV_MPU6880:
case INV_MPU9250: case INV_MPU9250:
case INV_MPU9255: case INV_MPU9255:
/* reset signal path (required for spi connection) */ /* reset signal path (required for spi connection) */
......
...@@ -177,6 +177,7 @@ static const struct i2c_device_id inv_mpu_id[] = { ...@@ -177,6 +177,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6050", INV_MPU6050}, {"mpu6050", INV_MPU6050},
{"mpu6500", INV_MPU6500}, {"mpu6500", INV_MPU6500},
{"mpu6515", INV_MPU6515}, {"mpu6515", INV_MPU6515},
{"mpu6880", INV_MPU6880},
{"mpu9150", INV_MPU9150}, {"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250}, {"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255}, {"mpu9255", INV_MPU9255},
...@@ -204,6 +205,10 @@ static const struct of_device_id inv_of_match[] = { ...@@ -204,6 +205,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,mpu6515", .compatible = "invensense,mpu6515",
.data = (void *)INV_MPU6515 .data = (void *)INV_MPU6515
}, },
{
.compatible = "invensense,mpu6880",
.data = (void *)INV_MPU6880
},
{ {
.compatible = "invensense,mpu9150", .compatible = "invensense,mpu9150",
.data = (void *)INV_MPU9150 .data = (void *)INV_MPU9150
......
...@@ -70,6 +70,7 @@ enum inv_devices { ...@@ -70,6 +70,7 @@ enum inv_devices {
INV_MPU6050, INV_MPU6050,
INV_MPU6500, INV_MPU6500,
INV_MPU6515, INV_MPU6515,
INV_MPU6880,
INV_MPU6000, INV_MPU6000,
INV_MPU9150, INV_MPU9150,
INV_MPU9250, INV_MPU9250,
...@@ -373,6 +374,7 @@ struct inv_mpu6050_state { ...@@ -373,6 +374,7 @@ struct inv_mpu6050_state {
#define INV_MPU6000_WHOAMI_VALUE 0x68 #define INV_MPU6000_WHOAMI_VALUE 0x68
#define INV_MPU6050_WHOAMI_VALUE 0x68 #define INV_MPU6050_WHOAMI_VALUE 0x68
#define INV_MPU6500_WHOAMI_VALUE 0x70 #define INV_MPU6500_WHOAMI_VALUE 0x70
#define INV_MPU6880_WHOAMI_VALUE 0x78
#define INV_MPU9150_WHOAMI_VALUE 0x68 #define INV_MPU9150_WHOAMI_VALUE 0x68
#define INV_MPU9250_WHOAMI_VALUE 0x71 #define INV_MPU9250_WHOAMI_VALUE 0x71
#define INV_MPU9255_WHOAMI_VALUE 0x73 #define INV_MPU9255_WHOAMI_VALUE 0x73
......
...@@ -70,6 +70,7 @@ static const struct spi_device_id inv_mpu_id[] = { ...@@ -70,6 +70,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000}, {"mpu6000", INV_MPU6000},
{"mpu6500", INV_MPU6500}, {"mpu6500", INV_MPU6500},
{"mpu6515", INV_MPU6515}, {"mpu6515", INV_MPU6515},
{"mpu6880", INV_MPU6880},
{"mpu9250", INV_MPU9250}, {"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255}, {"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608}, {"icm20608", INV_ICM20608},
...@@ -96,6 +97,10 @@ static const struct of_device_id inv_of_match[] = { ...@@ -96,6 +97,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,mpu6515", .compatible = "invensense,mpu6515",
.data = (void *)INV_MPU6515 .data = (void *)INV_MPU6515
}, },
{
.compatible = "invensense,mpu6880",
.data = (void *)INV_MPU6880
},
{ {
.compatible = "invensense,mpu9250", .compatible = "invensense,mpu9250",
.data = (void *)INV_MPU9250 .data = (void *)INV_MPU9250
......
...@@ -169,6 +169,36 @@ static const char * const iio_chan_info_postfix[] = { ...@@ -169,6 +169,36 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient", [IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient",
}; };
/**
* iio_sysfs_match_string_with_gaps - matches given string in an array with gaps
* @array: array of strings
* @n: number of strings in the array
* @str: string to match with
*
* Returns index of @str in the @array or -EINVAL, similar to match_string().
* Uses sysfs_streq instead of strcmp for matching.
*
* This routine will look for a string in an array of strings.
* The search will continue until the element is found or the n-th element
* is reached, regardless of any NULL elements in the array.
*/
static int iio_sysfs_match_string_with_gaps(const char * const *array, size_t n,
const char *str)
{
const char *item;
int index;
for (index = 0; index < n; index++) {
item = array[index];
if (!item)
continue;
if (sysfs_streq(item, str))
return index;
}
return -EINVAL;
}
#if defined(CONFIG_DEBUG_FS) #if defined(CONFIG_DEBUG_FS)
/* /*
* There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for * There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for
...@@ -470,8 +500,11 @@ ssize_t iio_enum_available_read(struct iio_dev *indio_dev, ...@@ -470,8 +500,11 @@ ssize_t iio_enum_available_read(struct iio_dev *indio_dev,
if (!e->num_items) if (!e->num_items)
return 0; return 0;
for (i = 0; i < e->num_items; ++i) for (i = 0; i < e->num_items; ++i) {
if (!e->items[i])
continue;
len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", e->items[i]); len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", e->items[i]);
}
/* replace last space with a newline */ /* replace last space with a newline */
buf[len - 1] = '\n'; buf[len - 1] = '\n';
...@@ -492,7 +525,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev, ...@@ -492,7 +525,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev,
i = e->get(indio_dev, chan); i = e->get(indio_dev, chan);
if (i < 0) if (i < 0)
return i; return i;
else if (i >= e->num_items) else if (i >= e->num_items || !e->items[i])
return -EINVAL; return -EINVAL;
return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]); return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]);
...@@ -509,7 +542,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, ...@@ -509,7 +542,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
if (!e->set) if (!e->set)
return -EINVAL; return -EINVAL;
ret = __sysfs_match_string(e->items, e->num_items, buf); ret = iio_sysfs_match_string_with_gaps(e->items, e->num_items, buf);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1473,11 +1506,14 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) ...@@ -1473,11 +1506,14 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
goto error_clear_attrs; goto error_clear_attrs;
} }
/* Copy across original attributes */ /* Copy across original attributes */
if (indio_dev->info->attrs) if (indio_dev->info->attrs) {
memcpy(iio_dev_opaque->chan_attr_group.attrs, memcpy(iio_dev_opaque->chan_attr_group.attrs,
indio_dev->info->attrs->attrs, indio_dev->info->attrs->attrs,
sizeof(iio_dev_opaque->chan_attr_group.attrs[0]) sizeof(iio_dev_opaque->chan_attr_group.attrs[0])
*attrcount_orig); *attrcount_orig);
iio_dev_opaque->chan_attr_group.is_visible =
indio_dev->info->attrs->is_visible;
}
attrn = attrcount_orig; attrn = attrcount_orig;
/* Add all elements from the list. */ /* Add all elements from the list. */
list_for_each_entry(p, &iio_dev_opaque->channel_attr_list, l) list_for_each_entry(p, &iio_dev_opaque->channel_attr_list, l)
......
...@@ -191,8 +191,8 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index) ...@@ -191,8 +191,8 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
return ERR_PTR(err); return ERR_PTR(err);
} }
static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
const char *name) const char *name)
{ {
struct iio_channel *chan = NULL; struct iio_channel *chan = NULL;
...@@ -230,6 +230,7 @@ static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, ...@@ -230,6 +230,7 @@ static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
return chan; return chan;
} }
EXPORT_SYMBOL_GPL(of_iio_channel_get_by_name);
static struct iio_channel *of_iio_channel_get_all(struct device *dev) static struct iio_channel *of_iio_channel_get_all(struct device *dev)
{ {
...@@ -272,12 +273,6 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev) ...@@ -272,12 +273,6 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev)
#else /* CONFIG_OF */ #else /* CONFIG_OF */
static inline struct iio_channel *
of_iio_channel_get_by_name(struct device_node *np, const char *name)
{
return NULL;
}
static inline struct iio_channel *of_iio_channel_get_all(struct device *dev) static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
{ {
return NULL; return NULL;
...@@ -393,6 +388,29 @@ struct iio_channel *devm_iio_channel_get(struct device *dev, ...@@ -393,6 +388,29 @@ struct iio_channel *devm_iio_channel_get(struct device *dev,
} }
EXPORT_SYMBOL_GPL(devm_iio_channel_get); EXPORT_SYMBOL_GPL(devm_iio_channel_get);
struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
struct device_node *np,
const char *channel_name)
{
struct iio_channel **ptr, *channel;
ptr = devres_alloc(devm_iio_channel_free, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
channel = of_iio_channel_get_by_name(np, channel_name);
if (IS_ERR(channel)) {
devres_free(ptr);
return channel;
}
*ptr = channel;
devres_add(dev, ptr);
return channel;
}
EXPORT_SYMBOL_GPL(devm_of_iio_channel_get_by_name);
struct iio_channel *iio_channel_get_all(struct device *dev) struct iio_channel *iio_channel_get_all(struct device *dev)
{ {
const char *name; const char *name;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* TODO: gesture + proximity calib offsets * TODO: gesture + proximity calib offsets
*/ */
#include <linux/acpi.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -1113,6 +1114,12 @@ static const struct i2c_device_id apds9960_id[] = { ...@@ -1113,6 +1114,12 @@ static const struct i2c_device_id apds9960_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, apds9960_id); MODULE_DEVICE_TABLE(i2c, apds9960_id);
static const struct acpi_device_id apds9960_acpi_match[] = {
{ "MSHW0184" },
{ }
};
MODULE_DEVICE_TABLE(acpi, apds9960_acpi_match);
static const struct of_device_id apds9960_of_match[] = { static const struct of_device_id apds9960_of_match[] = {
{ .compatible = "avago,apds9960" }, { .compatible = "avago,apds9960" },
{ } { }
...@@ -1124,6 +1131,7 @@ static struct i2c_driver apds9960_driver = { ...@@ -1124,6 +1131,7 @@ static struct i2c_driver apds9960_driver = {
.name = APDS9960_DRV_NAME, .name = APDS9960_DRV_NAME,
.of_match_table = apds9960_of_match, .of_match_table = apds9960_of_match,
.pm = &apds9960_pm_ops, .pm = &apds9960_pm_ops,
.acpi_match_table = apds9960_acpi_match,
}, },
.probe = apds9960_probe, .probe = apds9960_probe,
.remove = apds9960_remove, .remove = apds9960_remove,
......
...@@ -22,15 +22,21 @@ enum { ...@@ -22,15 +22,21 @@ enum {
CHANNEL_SCAN_INDEX_MAX CHANNEL_SCAN_INDEX_MAX
}; };
#define CHANNEL_SCAN_INDEX_TIMESTAMP CHANNEL_SCAN_INDEX_MAX
struct als_state { struct als_state {
struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes; struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info als_illum; struct hid_sensor_hub_attribute_info als_illum;
u32 illum[CHANNEL_SCAN_INDEX_MAX]; struct {
u32 illum[CHANNEL_SCAN_INDEX_MAX];
u64 timestamp __aligned(8);
} scan;
int scale_pre_decml; int scale_pre_decml;
int scale_post_decml; int scale_post_decml;
int scale_precision; int scale_precision;
int value_offset; int value_offset;
s64 timestamp;
}; };
/* Channel definitions */ /* Channel definitions */
...@@ -54,7 +60,8 @@ static const struct iio_chan_spec als_channels[] = { ...@@ -54,7 +60,8 @@ static const struct iio_chan_spec als_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM, .scan_index = CHANNEL_SCAN_INDEX_ILLUM,
} },
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
}; };
/* Adjust channel real bits based on report descriptor */ /* Adjust channel real bits based on report descriptor */
...@@ -168,14 +175,6 @@ static const struct iio_info als_info = { ...@@ -168,14 +175,6 @@ static const struct iio_info als_info = {
.write_raw = &als_write_raw, .write_raw = &als_write_raw,
}; };
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
int len)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
iio_push_to_buffers(indio_dev, data);
}
/* Callback handler to send event after all samples are received and captured */ /* Callback handler to send event after all samples are received and captured */
static int als_proc_event(struct hid_sensor_hub_device *hsdev, static int als_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id, unsigned usage_id,
...@@ -185,10 +184,14 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev, ...@@ -185,10 +184,14 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,
struct als_state *als_state = iio_priv(indio_dev); struct als_state *als_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "als_proc_event\n"); dev_dbg(&indio_dev->dev, "als_proc_event\n");
if (atomic_read(&als_state->common_attributes.data_ready)) if (atomic_read(&als_state->common_attributes.data_ready)) {
hid_sensor_push_data(indio_dev, if (!als_state->timestamp)
&als_state->illum, als_state->timestamp = iio_get_time_ns(indio_dev);
sizeof(als_state->illum));
iio_push_to_buffers_with_timestamp(indio_dev, &als_state->scan,
als_state->timestamp);
als_state->timestamp = 0;
}
return 0; return 0;
} }
...@@ -206,10 +209,14 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev, ...@@ -206,10 +209,14 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) { switch (usage_id) {
case HID_USAGE_SENSOR_LIGHT_ILLUM: case HID_USAGE_SENSOR_LIGHT_ILLUM:
als_state->illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data; als_state->scan.illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data;
als_state->illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data; als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
ret = 0; ret = 0;
break; break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
*(s64 *)raw_data);
break;
default: default:
break; break;
} }
......
...@@ -285,7 +285,7 @@ static int tsl2583_get_lux(struct iio_dev *indio_dev) ...@@ -285,7 +285,7 @@ static int tsl2583_get_lux(struct iio_dev *indio_dev)
lux64 = lux64 * chip->als_settings.als_gain_trim; lux64 = lux64 * chip->als_settings.als_gain_trim;
lux64 >>= 13; lux64 >>= 13;
lux = lux64; lux = lux64;
lux = (lux + 500) / 1000; lux = DIV_ROUND_CLOSEST(lux, 1000);
if (lux > TSL2583_LUX_CALC_OVER_FLOW) { /* check for overflow */ if (lux > TSL2583_LUX_CALC_OVER_FLOW) { /* check for overflow */
return_max: return_max:
...@@ -361,12 +361,12 @@ static int tsl2583_set_als_time(struct tsl2583_chip *chip) ...@@ -361,12 +361,12 @@ static int tsl2583_set_als_time(struct tsl2583_chip *chip)
u8 val; u8 val;
/* determine als integration register */ /* determine als integration register */
als_count = (chip->als_settings.als_time * 100 + 135) / 270; als_count = DIV_ROUND_CLOSEST(chip->als_settings.als_time * 100, 270);
if (!als_count) if (!als_count)
als_count = 1; /* ensure at least one cycle */ als_count = 1; /* ensure at least one cycle */
/* convert back to time (encompasses overrides) */ /* convert back to time (encompasses overrides) */
als_time = (als_count * 27 + 5) / 10; als_time = DIV_ROUND_CLOSEST(als_count * 27, 10);
val = 256 - als_count; val = 256 - als_count;
ret = i2c_smbus_write_byte_data(chip->client, ret = i2c_smbus_write_byte_data(chip->client,
...@@ -380,7 +380,7 @@ static int tsl2583_set_als_time(struct tsl2583_chip *chip) ...@@ -380,7 +380,7 @@ static int tsl2583_set_als_time(struct tsl2583_chip *chip)
/* set chip struct re scaling and saturation */ /* set chip struct re scaling and saturation */
chip->als_saturation = als_count * 922; /* 90% of full scale */ chip->als_saturation = als_count * 922; /* 90% of full scale */
chip->als_time_scale = (als_time + 25) / 50; chip->als_time_scale = DIV_ROUND_CLOSEST(als_time, 50);
return ret; return ret;
} }
......
...@@ -392,7 +392,7 @@ static int vl6180_set_it(struct vl6180_data *data, int val, int val2) ...@@ -392,7 +392,7 @@ static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
{ {
int ret, it_ms; int ret, it_ms;
it_ms = (val2 + 500) / 1000; /* round to ms */ it_ms = DIV_ROUND_CLOSEST(val2, 1000); /* round to ms */
if (val != 0 || it_ms < 1 || it_ms > 512) if (val != 0 || it_ms < 1 || it_ms > 512)
return -EINVAL; return -EINVAL;
......
...@@ -205,4 +205,19 @@ config SENSORS_RM3100_SPI ...@@ -205,4 +205,19 @@ config SENSORS_RM3100_SPI
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called rm3100-spi. will be called rm3100-spi.
config YAMAHA_YAS530
tristate "Yamaha YAS530 family of 3-Axis Magnetometers (I2C)"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here to add support for the Yamaha YAS530 series of
3-Axis Magnetometers. Right now YAS530, YAS532 and YAS533 are
fully supported.
This driver can also be compiled as a module.
To compile this driver as a module, choose M here: the module
will be called yamaha-yas.
endmenu endmenu
...@@ -28,3 +28,5 @@ obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o ...@@ -28,3 +28,5 @@ obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o
obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o
obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o
obj-$(CONFIG_YAMAHA_YAS530) += yamaha-yas530.o
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/iio/trigger_consumer.h> #include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "bmc150_magn.h" #include "bmc150_magn.h"
...@@ -135,6 +136,7 @@ struct bmc150_magn_data { ...@@ -135,6 +136,7 @@ struct bmc150_magn_data {
*/ */
struct mutex mutex; struct mutex mutex;
struct regmap *regmap; struct regmap *regmap;
struct regulator_bulk_data regulators[2];
struct iio_mount_matrix orientation; struct iio_mount_matrix orientation;
/* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */ /* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */
s32 buffer[6]; s32 buffer[6];
...@@ -692,12 +694,24 @@ static int bmc150_magn_init(struct bmc150_magn_data *data) ...@@ -692,12 +694,24 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
int ret, chip_id; int ret, chip_id;
struct bmc150_magn_preset preset; struct bmc150_magn_preset preset;
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret < 0) {
dev_err(data->dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
/*
* 3ms power-on time according to datasheet, let's better
* be safe than sorry and set this delay to 5ms.
*/
msleep(5);
ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND,
false); false);
if (ret < 0) { if (ret < 0) {
dev_err(data->dev, dev_err(data->dev,
"Failed to bring up device from suspend mode\n"); "Failed to bring up device from suspend mode\n");
return ret; goto err_regulator_disable;
} }
ret = regmap_read(data->regmap, BMC150_MAGN_REG_CHIP_ID, &chip_id); ret = regmap_read(data->regmap, BMC150_MAGN_REG_CHIP_ID, &chip_id);
...@@ -752,6 +766,8 @@ static int bmc150_magn_init(struct bmc150_magn_data *data) ...@@ -752,6 +766,8 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
err_poweroff: err_poweroff:
bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
err_regulator_disable:
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
return ret; return ret;
} }
...@@ -867,6 +883,13 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap, ...@@ -867,6 +883,13 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
data->irq = irq; data->irq = irq;
data->dev = dev; data->dev = dev;
data->regulators[0].supply = "vdd";
data->regulators[1].supply = "vddio";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
data->regulators);
if (ret)
return dev_err_probe(dev, ret, "failed to get regulators\n");
ret = iio_read_mount_matrix(dev, "mount-matrix", ret = iio_read_mount_matrix(dev, "mount-matrix",
&data->orientation); &data->orientation);
if (ret) if (ret)
...@@ -984,6 +1007,7 @@ int bmc150_magn_remove(struct device *dev) ...@@ -984,6 +1007,7 @@ int bmc150_magn_remove(struct device *dev)
bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
return 0; return 0;
} }
EXPORT_SYMBOL(bmc150_magn_remove); EXPORT_SYMBOL(bmc150_magn_remove);
......
...@@ -24,6 +24,7 @@ enum magn_3d_channel { ...@@ -24,6 +24,7 @@ enum magn_3d_channel {
CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP, CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
CHANNEL_SCAN_INDEX_NORTH_MAGN, CHANNEL_SCAN_INDEX_NORTH_MAGN,
CHANNEL_SCAN_INDEX_NORTH_TRUE, CHANNEL_SCAN_INDEX_NORTH_TRUE,
CHANNEL_SCAN_INDEX_TIMESTAMP,
MAGN_3D_CHANNEL_MAX, MAGN_3D_CHANNEL_MAX,
}; };
...@@ -47,6 +48,7 @@ struct magn_3d_state { ...@@ -47,6 +48,7 @@ struct magn_3d_state {
struct common_attributes magn_flux_attr; struct common_attributes magn_flux_attr;
struct common_attributes rot_attr; struct common_attributes rot_attr;
s64 timestamp;
}; };
static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
...@@ -57,6 +59,7 @@ static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { ...@@ -57,6 +59,7 @@ static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH, HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH,
HID_USAGE_SENSOR_ORIENT_MAGN_NORTH, HID_USAGE_SENSOR_ORIENT_MAGN_NORTH,
HID_USAGE_SENSOR_ORIENT_TRUE_NORTH, HID_USAGE_SENSOR_ORIENT_TRUE_NORTH,
HID_USAGE_SENSOR_TIME_TIMESTAMP,
}; };
/* Channel definitions */ /* Channel definitions */
...@@ -124,7 +127,8 @@ static const struct iio_chan_spec magn_3d_channels[] = { ...@@ -124,7 +127,8 @@ static const struct iio_chan_spec magn_3d_channels[] = {
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
} },
IIO_CHAN_SOFT_TIMESTAMP(7)
}; };
/* Adjust channel real bits based on report descriptor */ /* Adjust channel real bits based on report descriptor */
...@@ -273,13 +277,6 @@ static const struct iio_info magn_3d_info = { ...@@ -273,13 +277,6 @@ static const struct iio_info magn_3d_info = {
.write_raw = &magn_3d_write_raw, .write_raw = &magn_3d_write_raw,
}; };
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
iio_push_to_buffers(indio_dev, data);
}
/* Callback handler to send event after all samples are received and captured */ /* Callback handler to send event after all samples are received and captured */
static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id, unsigned usage_id,
...@@ -289,8 +286,15 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, ...@@ -289,8 +286,15 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
struct magn_3d_state *magn_state = iio_priv(indio_dev); struct magn_3d_state *magn_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
if (atomic_read(&magn_state->magn_flux_attributes.data_ready)) if (atomic_read(&magn_state->magn_flux_attributes.data_ready)) {
hid_sensor_push_data(indio_dev, magn_state->iio_vals); if (!magn_state->timestamp)
magn_state->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev,
magn_state->iio_vals,
magn_state->timestamp);
magn_state->timestamp = 0;
}
return 0; return 0;
} }
...@@ -321,6 +325,11 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, ...@@ -321,6 +325,11 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH) offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH)
+ CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP; + CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP;
break; break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
magn_state->timestamp =
hid_sensor_convert_timestamp(&magn_state->magn_flux_attributes,
*(s64 *)raw_data);
return ret;
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -386,9 +395,10 @@ static int magn_3d_parse_report(struct platform_device *pdev, ...@@ -386,9 +395,10 @@ static int magn_3d_parse_report(struct platform_device *pdev,
return -ENOMEM; return -ENOMEM;
} }
st->iio_vals = devm_kcalloc(&pdev->dev, attr_count, /* attr_count include timestamp channel, and the iio_vals should be aligned to 8byte */
sizeof(u32), st->iio_vals = devm_kcalloc(&pdev->dev,
GFP_KERNEL); ((attr_count + 1) % 2 + (attr_count + 1) / 2) * 2,
sizeof(u32), GFP_KERNEL);
if (!st->iio_vals) { if (!st->iio_vals) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to allocate space for iio values array\n"); "failed to allocate space for iio values array\n");
...@@ -404,11 +414,13 @@ static int magn_3d_parse_report(struct platform_device *pdev, ...@@ -404,11 +414,13 @@ static int magn_3d_parse_report(struct platform_device *pdev,
(_channels[*chan_count]).scan_index = *chan_count; (_channels[*chan_count]).scan_index = *chan_count;
(_channels[*chan_count]).address = i; (_channels[*chan_count]).address = i;
/* Set magn_val_addr to iio value address */ if (i != CHANNEL_SCAN_INDEX_TIMESTAMP) {
st->magn_val_addr[i] = &(st->iio_vals[*chan_count]); /* Set magn_val_addr to iio value address */
magn_3d_adjust_channel_bit_mask(_channels, st->magn_val_addr[i] = &st->iio_vals[*chan_count];
*chan_count, magn_3d_adjust_channel_bit_mask(_channels,
st->magn[i].size); *chan_count,
st->magn[i].size);
}
(*chan_count)++; (*chan_count)++;
} }
} }
......
This diff is collapsed.
...@@ -24,15 +24,21 @@ enum incl_3d_channel { ...@@ -24,15 +24,21 @@ enum incl_3d_channel {
INCLI_3D_CHANNEL_MAX, INCLI_3D_CHANNEL_MAX,
}; };
#define CHANNEL_SCAN_INDEX_TIMESTAMP INCLI_3D_CHANNEL_MAX
struct incl_3d_state { struct incl_3d_state {
struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes; struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX];
u32 incl_val[INCLI_3D_CHANNEL_MAX]; struct {
u32 incl_val[INCLI_3D_CHANNEL_MAX];
u64 timestamp __aligned(8);
} scan;
int scale_pre_decml; int scale_pre_decml;
int scale_post_decml; int scale_post_decml;
int scale_precision; int scale_precision;
int value_offset; int value_offset;
s64 timestamp;
}; };
static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = {
...@@ -73,7 +79,8 @@ static const struct iio_chan_spec incl_3d_channels[] = { ...@@ -73,7 +79,8 @@ static const struct iio_chan_spec incl_3d_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, .scan_index = CHANNEL_SCAN_INDEX_Z,
} },
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP),
}; };
/* Adjust channel real bits based on report descriptor */ /* Adjust channel real bits based on report descriptor */
...@@ -178,13 +185,6 @@ static const struct iio_info incl_3d_info = { ...@@ -178,13 +185,6 @@ static const struct iio_info incl_3d_info = {
.write_raw = &incl_3d_write_raw, .write_raw = &incl_3d_write_raw,
}; };
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */ /* Callback handler to send event after all samples are received and captured */
static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id, unsigned usage_id,
...@@ -194,10 +194,16 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, ...@@ -194,10 +194,16 @@ static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
struct incl_3d_state *incl_state = iio_priv(indio_dev); struct incl_3d_state *incl_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "incl_3d_proc_event\n"); dev_dbg(&indio_dev->dev, "incl_3d_proc_event\n");
if (atomic_read(&incl_state->common_attributes.data_ready)) if (atomic_read(&incl_state->common_attributes.data_ready)) {
hid_sensor_push_data(indio_dev, if (!incl_state->timestamp)
(u8 *)incl_state->incl_val, incl_state->timestamp = iio_get_time_ns(indio_dev);
sizeof(incl_state->incl_val));
iio_push_to_buffers_with_timestamp(indio_dev,
&incl_state->scan,
incl_state->timestamp);
incl_state->timestamp = 0;
}
return 0; return 0;
} }
...@@ -214,13 +220,18 @@ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, ...@@ -214,13 +220,18 @@ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) { switch (usage_id) {
case HID_USAGE_SENSOR_ORIENT_TILT_X: case HID_USAGE_SENSOR_ORIENT_TILT_X:
incl_state->incl_val[CHANNEL_SCAN_INDEX_X] = *(u32 *)raw_data; incl_state->scan.incl_val[CHANNEL_SCAN_INDEX_X] = *(u32 *)raw_data;
break; break;
case HID_USAGE_SENSOR_ORIENT_TILT_Y: case HID_USAGE_SENSOR_ORIENT_TILT_Y:
incl_state->incl_val[CHANNEL_SCAN_INDEX_Y] = *(u32 *)raw_data; incl_state->scan.incl_val[CHANNEL_SCAN_INDEX_Y] = *(u32 *)raw_data;
break; break;
case HID_USAGE_SENSOR_ORIENT_TILT_Z: case HID_USAGE_SENSOR_ORIENT_TILT_Z:
incl_state->incl_val[CHANNEL_SCAN_INDEX_Z] = *(u32 *)raw_data; incl_state->scan.incl_val[CHANNEL_SCAN_INDEX_Z] = *(u32 *)raw_data;
break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
incl_state->timestamp =
hid_sensor_convert_timestamp(&incl_state->common_attributes,
*(s64 *)raw_data);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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