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:
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_anglY_raw
KernelVersion: 4.17
Contact: linux-iio@vger.kernel.org
Description:
......@@ -1812,3 +1813,13 @@ Contact: linux-iio@vger.kernel.org
Description:
Unscaled light intensity according to CIE 1931/DIN 5033 color space.
Units after application of scale are nano nanowatts per square meter.
What: /sys/bus/iio/devices/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:
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
mount-matrix:
description: an optional 3x3 mounting rotation matrix.
......
Xilinx XADC device driver
This binding document describes the bindings for both of them since the
bindings are very similar. The Xilinx XADC is a ADC that can be found in the
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
available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The
other one is available 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.
This binding document describes the bindings for the Xilinx 7 Series XADC as well
as the UltraScale/UltraScale+ System Monitor.
The Xilinx XADC is an ADC that can be found in the 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 available on the ZYNQ
family as a hardmacro in the SoC portion of the ZYNQ. The other one is available
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:
- compatible: Should be one of
......@@ -15,11 +24,14 @@ Required properties:
configuration interface to interface to the XADC hardmacro.
* "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to
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
- interrupts: Interrupt for the XADC control interface.
- 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
clock to the AXI bus interface of the core.
when using the axi-xadc or the axi-system-management-wizard this must be
the clock that provides the clock to the AXI bus interface of the core.
Optional properties:
- xlnx,external-mux:
......@@ -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:
allOf:
- if:
not:
properties:
compatible:
contains:
const: microchip,mcp4726
properties:
compatible:
contains:
const: microchip,mcp4725
then:
properties:
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
required:
- compatible
- reg
- vdd-supply
additionalProperties: false
......
......@@ -19,6 +19,9 @@ properties:
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
interrupts:
minItems: 1
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:
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
interrupts:
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:
- maxim,max31730
# mCube 3-axis 8-bit digital accelerometer
- mcube,mc3230
# MEMSIC magnetometer
- memsic,mmc35240
# MEMSIC 2-axis 8-bit digital accelerometer
- memsic,mxc6225
# Measurement Specialities I2C temperature and humidity sensor
- meas,htu21
# Measurement Specialities I2C pressure and temperature sensor
- meas,ms5637
# Measurement Specialities I2C pressure and temperature sensor
- meas,ms5803
# Measurement Specialities I2C pressure and temperature sensor
- meas,ms5805
# Measurement Specialities I2C pressure and temperature sensor
- meas,ms5837
......@@ -166,6 +164,10 @@ properties:
- meas,ms8607-temppressure
# Measurement Specialties temperature sensor
- meas,tsys01
# MEMSIC magnetometer
- memsic,mmc35240
# MEMSIC 2-axis 8-bit digital accelerometer
- memsic,mxc6225
# Microchip differential I2C ADC, 1 Channel, 18 bit
- microchip,mcp3421
# Microchip differential I2C ADC, 2 Channel, 18 bit
......
......@@ -1252,6 +1252,8 @@ patternProperties:
description: Shenzhen Xunlong Software CO.,Limited
"^xylon,.*":
description: Xylon
"^yamaha,.*":
description: Yamaha Corporation
"^yes-optoelectronics,.*":
description: Yes Optoelectronics Co.,Ltd.
"^ylm,.*":
......
......@@ -4,6 +4,7 @@
* Copyright (c) 2015, Intel Corporation.
*/
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
......@@ -21,6 +22,7 @@
#define HID_CUSTOM_TOTAL_ATTRS (HID_CUSTOM_MAX_CORE_ATTRS + 1)
#define HID_CUSTOM_FIFO_SIZE 4096
#define HID_CUSTOM_MAX_FEATURE_BYTES 64
#define HID_SENSOR_USAGE_LENGTH (4 + 1)
struct hid_sensor_custom_field {
int report_id;
......@@ -50,6 +52,7 @@ struct hid_sensor_custom {
struct kfifo data_fifo;
unsigned long misc_opened;
wait_queue_head_t wait;
struct platform_device *custom_pdev;
};
/* 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
}
/* 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)
{
struct hid_sensor_custom *sensor_inst;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
int ret;
int index;
sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
GFP_KERNEL);
......@@ -764,6 +886,22 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
sensor_inst->pdev = pdev;
mutex_init(&sensor_inst->mutex);
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,
&sensor_inst->callbacks);
if (ret < 0) {
......@@ -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_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_remove_attributes(sensor_inst);
sysfs_remove_group(&sensor_inst->pdev->dev.kobj,
......
......@@ -23,6 +23,7 @@ enum accel_3d_channel {
ACCEL_3D_CHANNEL_MAX,
};
#define CHANNEL_SCAN_INDEX_TIMESTAMP ACCEL_3D_CHANNEL_MAX
struct accel_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
......@@ -75,7 +76,7 @@ static const struct iio_chan_spec accel_3d_channels[] = {
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
},
IIO_CHAN_SOFT_TIMESTAMP(3)
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
/* Channel definitions */
......@@ -110,7 +111,8 @@ static const struct iio_chan_spec gravity_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
},
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP),
};
/* Adjust channel real bits based on report descriptor */
......
......@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
......@@ -133,6 +134,7 @@ enum kx_acpi_type {
};
struct kxcjk1013_data {
struct regulator_bulk_data regulators[2];
struct i2c_client *client;
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
......@@ -1300,6 +1302,13 @@ static const char *kxcjk1013_match_acpi_device(struct device *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,
const struct i2c_device_id *id)
{
......@@ -1330,6 +1339,29 @@ static int kxcjk1013_probe(struct i2c_client *client,
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) {
data->chipset = (enum kx_chipset)(id->driver_data);
name = id->name;
......
......@@ -1228,8 +1228,15 @@ config XILINX_XADC
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to have support for the Xilinx XADC. The driver does support
both the ZYNQ interface to the XADC as well as the AXI-XADC interface.
Say yes here to have support for the Xilinx 7 Series XADC or
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
xilinx-xadc.
......
......@@ -1108,10 +1108,14 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
return gpadc->irq_sw;
}
gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
if (gpadc->irq_hw < 0) {
dev_err(dev, "failed to get platform hw_conv_end irq\n");
return gpadc->irq_hw;
if (is_ab8500(gpadc->ab8500)) {
gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
if (gpadc->irq_hw < 0) {
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 */
......@@ -1128,14 +1132,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
return ret;
}
ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL,
ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
"ab8500-gpadc-hw", gpadc);
if (ret < 0) {
dev_err(dev,
"Failed to request hw conversion irq: %d\n",
gpadc->irq_hw);
return ret;
if (gpadc->irq_hw) {
ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL,
ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
"ab8500-gpadc-hw", gpadc);
if (ret < 0) {
dev_err(dev,
"Failed to request hw conversion irq: %d\n",
gpadc->irq_hw);
return ret;
}
}
/* The VTVout LDO used to power the AB8500 GPADC */
......
......@@ -67,6 +67,7 @@ enum ad7476_supported_device_ids {
ID_ADS7866,
ID_ADS7867,
ID_ADS7868,
ID_LTC2314_14,
};
static void ad7091_convst(struct ad7476_state *st)
......@@ -250,6 +251,10 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = ADS786X_CHAN(8),
.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 = {
......@@ -365,6 +370,7 @@ static const struct spi_device_id ad7476_id[] = {
{"ads7866", ID_ADS7866},
{"ads7867", ID_ADS7867},
{"ads7868", ID_ADS7868},
{"ltc2314-14", ID_LTC2314_14},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
......
......@@ -10,6 +10,7 @@
* Author: Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
......@@ -21,8 +22,6 @@
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
#include "qcom-vadc-common.h"
/*
* Definitions for the "user processor" registers lifted from the v3.4
* Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC:
......
......@@ -7,6 +7,7 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
......@@ -14,12 +15,12 @@
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include "qcom-vadc-common.h"
#define ADC5_USR_REVISION1 0x0
#define ADC5_USR_STATUS1 0x8
......@@ -154,18 +155,6 @@ struct adc5_chip {
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)
{
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)
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)
{
int ret;
......@@ -511,7 +451,7 @@ static int adc_read_raw_common(struct iio_dev *indio_dev,
return ret;
ret = qcom_adc5_hw_scale(prop->scale_fn_type,
&adc5_prescale_ratios[prop->prescale],
prop->prescale,
adc->data,
adc_code_volt, val);
if (ret)
......@@ -717,7 +657,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
ret = of_property_read_u32(node, "qcom,decimation", &value);
if (!ret) {
ret = adc5_decimation_from_dt(value, data->decimation);
ret = qcom_adc5_decimation_from_dt(value, data->decimation);
if (ret < 0) {
dev_err(dev, "%02x invalid decimation %d\n",
chan, value);
......@@ -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);
if (!ret) {
ret = adc5_prescaling_from_dt(varr[0], varr[1]);
ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
if (ret < 0) {
dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
chan, varr[0], varr[1]);
......@@ -759,11 +699,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
if ((dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR &&
dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR) ||
adc->data->info == &adc7_info)
ret = adc5_hw_settle_time_from_dt(value,
data->hw_settle_2);
ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_2);
else
ret = adc5_hw_settle_time_from_dt(value,
data->hw_settle_1);
ret = qcom_adc5_hw_settle_time_from_dt(value, data->hw_settle_1);
if (ret < 0) {
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,
ret = of_property_read_u32(node, "qcom,avg-samples", &value);
if (!ret) {
ret = adc5_avg_samples_from_dt(value);
ret = qcom_adc5_avg_samples_from_dt(value);
if (ret < 0) {
dev_err(dev, "%02x invalid avg-samples %d\n",
chan, value);
......@@ -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 device_node *child;
unsigned int index = 0;
const struct of_device_id *id;
const struct adc5_data *data;
int ret;
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)
chan_props = adc->chan_props;
iio_chan = adc->iio_chans;
id = of_match_node(adc5_match_table, node);
if (id)
data = id->data;
else
data = &adc5_data_pmic;
adc->data = data;
adc->data = of_device_get_match_data(adc->dev);
if (!adc->data)
adc->data = &adc5_data_pmic;
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) {
of_node_put(child);
return ret;
}
prop.scale_fn_type =
data->adc_chans[prop.channel].scale_fn_type;
adc->data->adc_chans[prop.channel].scale_fn_type;
*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->datasheet_name = prop.datasheet_name;
......
......@@ -7,6 +7,7 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
......@@ -20,8 +21,6 @@
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include "qcom-vadc-common.h"
/* VADC register and bit definitions */
#define VADC_REVISION2 0x1
#define VADC_REVISION2_SUPPORTED_VADC 1
......
......@@ -2,50 +2,61 @@
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/fixp-arith.h>
#include <linux/iio/adc/qcom-vadc-common.h>
#include <linux/math64.h>
#include <linux/log2.h>
#include <linux/err.h>
#include <linux/module.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 */
static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
{1758, -40},
{1742, -35},
{1719, -30},
{1691, -25},
{1654, -20},
{1608, -15},
{1551, -10},
{1483, -5},
{1404, 0},
{1315, 5},
{1218, 10},
{1114, 15},
{1007, 20},
{900, 25},
{795, 30},
{696, 35},
{605, 40},
{522, 45},
{448, 50},
{383, 55},
{327, 60},
{278, 65},
{237, 70},
{202, 75},
{172, 80},
{146, 85},
{125, 90},
{107, 95},
{92, 100},
{79, 105},
{68, 110},
{59, 115},
{51, 120},
{44, 125}
{1758, -40000 },
{1742, -35000 },
{1719, -30000 },
{1691, -25000 },
{1654, -20000 },
{1608, -15000 },
{1551, -10000 },
{1483, -5000 },
{1404, 0 },
{1315, 5000 },
{1218, 10000 },
{1114, 15000 },
{1007, 20000 },
{900, 25000 },
{795, 30000 },
{696, 35000 },
{605, 40000 },
{522, 45000 },
{448, 50000 },
{383, 55000 },
{327, 60000 },
{278, 65000 },
{237, 70000 },
{202, 75000 },
{172, 80000 },
{146, 85000 },
{125, 90000 },
{107, 95000 },
{92, 100000 },
{79, 105000 },
{68, 110000 },
{59, 115000 },
{51, 120000 },
{44, 125000 }
};
/*
......@@ -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[] = {
{ 433700, 1967},
{ 473100, 1964},
{ 512400, 1957},
{ 551500, 1949},
{ 590500, 1940},
{ 629300, 1930},
{ 667900, 1921},
{ 706400, 1910},
{ 744600, 1896},
{ 782500, 1878},
{ 820100, 1859},
{ 857300, 0},
{ 857300, 160000 },
{ 820100, 140000 },
{ 782500, 120000 },
{ 744600, 100000 },
{ 706400, 80000 },
{ 667900, 60000 },
{ 629300, 40000 },
{ 590500, 20000 },
{ 551500, 0 },
{ 512400, -20000 },
{ 473100, -40000 },
{ 433700, -60000 },
};
/*
......@@ -278,6 +289,18 @@ static const struct vadc_map_pt adcmap7_100k[] = {
{ 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(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
......@@ -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,
u32 tablesize, s32 input, int *output)
{
bool descending = 1;
u32 i = 0;
if (!pts)
return -EINVAL;
/* Check if table is descending or ascending */
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;
}
while (i < tablesize && pts[i].x > input)
i++;
}
if (i == 0) {
*output = pts[0].y;
} else if (i == tablesize) {
*output = pts[tablesize - 1].y;
} else {
/* result is between search_index and search_index-1 */
/* interpolate linearly */
*output = (((s32)((pts[i].y - pts[i - 1].y) *
(input - pts[i - 1].x)) /
(pts[i].x - pts[i - 1].x)) +
pts[i - 1].y);
*output = fixp_linear_interpolate(pts[i - 1].x, pts[i - 1].y,
pts[i].x, pts[i].y,
input);
}
return 0;
......@@ -415,8 +418,6 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
if (ret)
return ret;
*result_mdec *= 1000;
return 0;
}
......@@ -563,33 +564,13 @@ static int qcom_vadc7_scale_hw_calib_die_temp(
u16 adc_code, int *result_mdec)
{
int voltage, vtemp0, temp, i;
int voltage;
voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
prescale, data, 1);
if (adcmap7_die_temp[0].x > voltage) {
*result_mdec = DIE_TEMP_ADC7_SCALE_1;
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;
return qcom_vadc_map_voltage_temp(adcmap7_die_temp, ARRAY_SIZE(adcmap7_die_temp),
voltage, result_mdec);
}
static int qcom_vadc_scale_hw_smb_temp(
......@@ -647,10 +628,12 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
EXPORT_SYMBOL(qcom_vadc_scale);
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,
u16 adc_code, int *result)
{
const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio];
if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
scaletype < SCALE_HW_CALIB_INVALID)) {
pr_err("Invalid scale type %d\n", scaletype);
......@@ -662,6 +645,58 @@ int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
}
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)
{
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,
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,
......
......@@ -535,20 +535,16 @@ static int stm32_adc_core_hw_start(struct device *dev)
goto err_switches_dis;
}
if (priv->bclk) {
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(dev, "bus clk enable failed\n");
goto err_regulator_disable;
}
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(dev, "bus clk enable failed\n");
goto err_regulator_disable;
}
if (priv->aclk) {
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(dev, "adc clk enable failed\n");
goto err_bclk_disable;
}
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(dev, "adc clk enable failed\n");
goto err_bclk_disable;
}
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)
return 0;
err_bclk_disable:
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
clk_disable_unprepare(priv->bclk);
err_regulator_disable:
regulator_disable(priv->vref);
err_switches_dis:
......@@ -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) */
priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
clk_disable_unprepare(priv->aclk);
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref);
stm32_adc_core_switches_supply_dis(priv);
regulator_disable(priv->vdda);
......
......@@ -546,8 +546,7 @@ static int stm32_adc_hw_stop(struct device *dev)
if (adc->cfg->unprepare)
adc->cfg->unprepare(indio_dev);
if (adc->clk)
clk_disable_unprepare(adc->clk);
clk_disable_unprepare(adc->clk);
return 0;
}
......@@ -558,11 +557,9 @@ static int stm32_adc_hw_start(struct device *dev)
struct stm32_adc *adc = iio_priv(indio_dev);
int ret;
if (adc->clk) {
ret = clk_prepare_enable(adc->clk);
if (ret)
return ret;
}
ret = clk_prepare_enable(adc->clk);
if (ret)
return ret;
stm32_adc_set_res(adc);
......@@ -575,8 +572,7 @@ static int stm32_adc_hw_start(struct device *dev)
return 0;
err_clk_dis:
if (adc->clk)
clk_disable_unprepare(adc->clk);
clk_disable_unprepare(adc->clk);
return ret;
}
......
......@@ -117,8 +117,7 @@ static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *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);
}
......
This diff is collapsed.
......@@ -155,9 +155,6 @@ int xadc_write_event_config(struct iio_dev *indio_dev,
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,
const struct iio_chan_spec *chan, enum iio_event_type type,
enum iio_event_direction dir, enum iio_event_info info,
......@@ -177,7 +174,8 @@ int xadc_read_event_value(struct iio_dev *indio_dev,
return -EINVAL;
}
*val >>= XADC_THRESHOLD_VALUE_SHIFT;
/* MSB aligned */
*val >>= 16 - chan->scan_type.realbits;
return IIO_VAL_INT;
}
......@@ -191,7 +189,8 @@ int xadc_write_event_value(struct iio_dev *indio_dev,
struct xadc *xadc = iio_priv(indio_dev);
int ret = 0;
val <<= XADC_THRESHOLD_VALUE_SHIFT;
/* MSB aligned */
val <<= 16 - chan->scan_type.realbits;
if (val < 0 || val > 0xffff)
return -EINVAL;
......
......@@ -70,6 +70,11 @@ struct xadc {
int irq;
};
enum xadc_type {
XADC_TYPE_S7, /* Series 7 */
XADC_TYPE_US, /* UltraScale and UltraScale+ */
};
struct xadc_ops {
int (*read)(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 {
irqreturn_t (*interrupt_handler)(int irq, void *devid);
unsigned int flags;
enum xadc_type type;
};
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)
var4 = (var3 / (calib->res_heat_range + 4));
var5 = 131 * calib->res_heat_val + 65536;
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;
}
......
......@@ -282,7 +282,7 @@ static int pms7003_probe(struct serdev_device *serdev)
state->serdev = serdev;
indio_dev->info = &pms7003_info;
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->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = pms7003_scan_masks;
......
......@@ -71,6 +71,8 @@ static struct {
{HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 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,
......
......@@ -488,24 +488,20 @@ int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
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.
* This function is only used when reading PROM coefficients
*
* @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;
u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
prom[len - 1] = 0;
prom[0] &= 0x0FFF; /* Clear the CRC computation part */
u16 n_rem = 0x0000;
for (cnt = 0; cnt < len * 2; cnt++) {
for (cnt = 0; cnt < MS_SENSORS_TP_PROM_WORDS_NB * 2; cnt++) {
if (cnt % 2 == 1)
n_rem ^= prom[cnt >> 1] & 0x00FF;
else
......@@ -518,10 +514,55 @@ static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
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)
int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
{
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(
dev_data->client,
MS_SENSORS_TP_PROM_READ + (i << 1),
......@@ -547,8 +589,12 @@ int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
return ret;
}
if (!ms_sensors_tp_crc_valid(dev_data->prom,
MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
if (dev_data->hw->prom_len == 8)
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,
"Calibration coefficients crc check error\n");
return -ENODEV;
......
......@@ -11,7 +11,7 @@
#include <linux/i2c.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
......@@ -25,6 +25,16 @@ struct ms_ht_dev {
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
* @client: i2c client
......@@ -36,7 +46,8 @@ struct ms_ht_dev {
struct ms_tp_dev {
struct i2c_client *client;
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;
};
......
......@@ -189,6 +189,16 @@ config AD5764
To compile this driver as a module, choose M here: the
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
tristate "Analog Devices AD5770R IDAC driver"
depends on SPI_MASTER
......
......@@ -19,6 +19,7 @@ obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5755) += ad5758.o
obj-$(CONFIG_AD5761) += ad5761.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5766) += ad5766.o
obj-$(CONFIG_AD5770R) += ad5770r.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
......
This diff is collapsed.
......@@ -582,8 +582,7 @@ static int adf4350_probe(struct spi_device *spi)
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
error_disable_clk:
if (clk)
clk_disable_unprepare(clk);
clk_disable_unprepare(clk);
return ret;
}
......@@ -599,8 +598,7 @@ static int adf4350_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
if (st->clk)
clk_disable_unprepare(st->clk);
clk_disable_unprepare(st->clk);
if (!IS_ERR(reg))
regulator_disable(reg);
......
......@@ -19,6 +19,7 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "bmg160.h"
#define BMG160_IRQ_NAME "bmg160_event"
......@@ -92,6 +93,7 @@
struct bmg160_data {
struct regmap *regmap;
struct regulator_bulk_data regulators[2];
struct iio_trigger *dready_trig;
struct iio_trigger *motion_trig;
struct iio_mount_matrix orientation;
......@@ -1061,6 +1063,13 @@ static const char *bmg160_match_acpi_device(struct device *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,
const char *name)
{
......@@ -1077,6 +1086,22 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
data->irq = irq;
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",
&data->orientation);
if (ret)
......
......@@ -23,15 +23,20 @@ enum gyro_3d_channel {
GYRO_3D_CHANNEL_MAX,
};
#define CHANNEL_SCAN_INDEX_TIMESTAMP GYRO_3D_CHANNEL_MAX
struct gyro_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
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_post_decml;
int scale_precision;
int value_offset;
s64 timestamp;
};
static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = {
......@@ -72,7 +77,8 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
},
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
/* Adjust channel real bits based on report descriptor */
......@@ -178,14 +184,6 @@ static const struct iio_info gyro_3d_info = {
.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 */
static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
......@@ -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);
dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n");
if (atomic_read(&gyro_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev,
gyro_state->gyro_val,
sizeof(gyro_state->gyro_val));
if (atomic_read(&gyro_state->common_attributes.data_ready)) {
if (!gyro_state->timestamp)
gyro_state->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev, &gyro_state->scan,
gyro_state->timestamp);
gyro_state->timestamp = 0;
}
return 0;
}
......@@ -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_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS;
gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data;
gyro_state->scan.gyro_val[CHANNEL_SCAN_INDEX_X + offset] =
*(u32 *)raw_data;
ret = 0;
break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
gyro_state->timestamp =
hid_sensor_convert_timestamp(&gyro_state->common_attributes,
*(s64 *)raw_data);
break;
default:
break;
}
......
......@@ -16,8 +16,8 @@ config INV_MPU6050_I2C
select REGMAP_I2C
help
This driver supports the Invensense MPU6050/9150,
MPU6500/6515/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690 and
IAM20680 motion tracking devices over I2C.
MPU6500/6515/6880/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690
and IAM20680 motion tracking devices over I2C.
This driver can be built as a module. The module will be called
inv-mpu6050-i2c.
......@@ -28,7 +28,7 @@ config INV_MPU6050_SPI
select REGMAP_SPI
help
This driver supports the Invensense MPU6000,
MPU6500/6515/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690 and
IAM20680 motion tracking devices over SPI.
MPU6500/6515/6880/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690
and IAM20680 motion tracking devices over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.
......@@ -160,6 +160,14 @@ static const struct inv_mpu6050_hw hw_info[] = {
.fifo_size = 512,
.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,
.name = "MPU6000",
......@@ -1323,6 +1331,7 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
case INV_MPU6000:
case INV_MPU6500:
case INV_MPU6515:
case INV_MPU6880:
case INV_MPU9250:
case INV_MPU9255:
/* reset signal path (required for spi connection) */
......
......@@ -177,6 +177,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6050", INV_MPU6050},
{"mpu6500", INV_MPU6500},
{"mpu6515", INV_MPU6515},
{"mpu6880", INV_MPU6880},
{"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
......@@ -204,6 +205,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,mpu6515",
.data = (void *)INV_MPU6515
},
{
.compatible = "invensense,mpu6880",
.data = (void *)INV_MPU6880
},
{
.compatible = "invensense,mpu9150",
.data = (void *)INV_MPU9150
......
......@@ -70,6 +70,7 @@ enum inv_devices {
INV_MPU6050,
INV_MPU6500,
INV_MPU6515,
INV_MPU6880,
INV_MPU6000,
INV_MPU9150,
INV_MPU9250,
......@@ -373,6 +374,7 @@ struct inv_mpu6050_state {
#define INV_MPU6000_WHOAMI_VALUE 0x68
#define INV_MPU6050_WHOAMI_VALUE 0x68
#define INV_MPU6500_WHOAMI_VALUE 0x70
#define INV_MPU6880_WHOAMI_VALUE 0x78
#define INV_MPU9150_WHOAMI_VALUE 0x68
#define INV_MPU9250_WHOAMI_VALUE 0x71
#define INV_MPU9255_WHOAMI_VALUE 0x73
......
......@@ -70,6 +70,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000},
{"mpu6500", INV_MPU6500},
{"mpu6515", INV_MPU6515},
{"mpu6880", INV_MPU6880},
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},
......@@ -96,6 +97,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,mpu6515",
.data = (void *)INV_MPU6515
},
{
.compatible = "invensense,mpu6880",
.data = (void *)INV_MPU6880
},
{
.compatible = "invensense,mpu9250",
.data = (void *)INV_MPU9250
......
......@@ -169,6 +169,36 @@ static const char * const iio_chan_info_postfix[] = {
[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)
/*
* 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,
if (!e->num_items)
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]);
}
/* replace last space with a newline */
buf[len - 1] = '\n';
......@@ -492,7 +525,7 @@ ssize_t iio_enum_read(struct iio_dev *indio_dev,
i = e->get(indio_dev, chan);
if (i < 0)
return i;
else if (i >= e->num_items)
else if (i >= e->num_items || !e->items[i])
return -EINVAL;
return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]);
......@@ -509,7 +542,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
if (!e->set)
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)
return ret;
......@@ -1473,11 +1506,14 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
goto error_clear_attrs;
}
/* Copy across original attributes */
if (indio_dev->info->attrs)
if (indio_dev->info->attrs) {
memcpy(iio_dev_opaque->chan_attr_group.attrs,
indio_dev->info->attrs->attrs,
sizeof(iio_dev_opaque->chan_attr_group.attrs[0])
*attrcount_orig);
iio_dev_opaque->chan_attr_group.is_visible =
indio_dev->info->attrs->is_visible;
}
attrn = attrcount_orig;
/* Add all elements from the list. */
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)
return ERR_PTR(err);
}
static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
const char *name)
struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
const char *name)
{
struct iio_channel *chan = NULL;
......@@ -230,6 +230,7 @@ static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
return chan;
}
EXPORT_SYMBOL_GPL(of_iio_channel_get_by_name);
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 */
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)
{
return NULL;
......@@ -393,6 +388,29 @@ struct iio_channel *devm_iio_channel_get(struct device *dev,
}
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)
{
const char *name;
......
......@@ -8,6 +8,7 @@
* TODO: gesture + proximity calib offsets
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
......@@ -1113,6 +1114,12 @@ static const struct i2c_device_id 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[] = {
{ .compatible = "avago,apds9960" },
{ }
......@@ -1124,6 +1131,7 @@ static struct i2c_driver apds9960_driver = {
.name = APDS9960_DRV_NAME,
.of_match_table = apds9960_of_match,
.pm = &apds9960_pm_ops,
.acpi_match_table = apds9960_acpi_match,
},
.probe = apds9960_probe,
.remove = apds9960_remove,
......
......@@ -22,15 +22,21 @@ enum {
CHANNEL_SCAN_INDEX_MAX
};
#define CHANNEL_SCAN_INDEX_TIMESTAMP CHANNEL_SCAN_INDEX_MAX
struct als_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
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_post_decml;
int scale_precision;
int value_offset;
s64 timestamp;
};
/* Channel definitions */
......@@ -54,7 +60,8 @@ static const struct iio_chan_spec als_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
}
},
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
/* Adjust channel real bits based on report descriptor */
......@@ -168,14 +175,6 @@ static const struct iio_info als_info = {
.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 */
static int als_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
......@@ -185,10 +184,14 @@ static int als_proc_event(struct hid_sensor_hub_device *hsdev,
struct als_state *als_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "als_proc_event\n");
if (atomic_read(&als_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev,
&als_state->illum,
sizeof(als_state->illum));
if (atomic_read(&als_state->common_attributes.data_ready)) {
if (!als_state->timestamp)
als_state->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev, &als_state->scan,
als_state->timestamp);
als_state->timestamp = 0;
}
return 0;
}
......@@ -206,10 +209,14 @@ static int als_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) {
case HID_USAGE_SENSOR_LIGHT_ILLUM:
als_state->illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data;
als_state->illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
als_state->scan.illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data;
als_state->scan.illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
ret = 0;
break;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
als_state->timestamp = hid_sensor_convert_timestamp(&als_state->common_attributes,
*(s64 *)raw_data);
break;
default:
break;
}
......
......@@ -285,7 +285,7 @@ static int tsl2583_get_lux(struct iio_dev *indio_dev)
lux64 = lux64 * chip->als_settings.als_gain_trim;
lux64 >>= 13;
lux = lux64;
lux = (lux + 500) / 1000;
lux = DIV_ROUND_CLOSEST(lux, 1000);
if (lux > TSL2583_LUX_CALC_OVER_FLOW) { /* check for overflow */
return_max:
......@@ -361,12 +361,12 @@ static int tsl2583_set_als_time(struct tsl2583_chip *chip)
u8 val;
/* 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)
als_count = 1; /* ensure at least one cycle */
/* 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;
ret = i2c_smbus_write_byte_data(chip->client,
......@@ -380,7 +380,7 @@ static int tsl2583_set_als_time(struct tsl2583_chip *chip)
/* set chip struct re scaling and saturation */
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;
}
......
......@@ -392,7 +392,7 @@ static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
{
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)
return -EINVAL;
......
......@@ -205,4 +205,19 @@ config SENSORS_RM3100_SPI
To compile this driver as a module, choose M here: the module
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
......@@ -28,3 +28,5 @@ obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o
obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o
obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o
obj-$(CONFIG_YAMAHA_YAS530) += yamaha-yas530.o
......@@ -25,6 +25,7 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "bmc150_magn.h"
......@@ -135,6 +136,7 @@ struct bmc150_magn_data {
*/
struct mutex mutex;
struct regmap *regmap;
struct regulator_bulk_data regulators[2];
struct iio_mount_matrix orientation;
/* 4 x 32 bits for x, y z, 4 bytes align, 64 bits timestamp */
s32 buffer[6];
......@@ -692,12 +694,24 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
int ret, chip_id;
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,
false);
if (ret < 0) {
dev_err(data->dev,
"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);
......@@ -752,6 +766,8 @@ static int bmc150_magn_init(struct bmc150_magn_data *data)
err_poweroff:
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;
}
......@@ -867,6 +883,13 @@ int bmc150_magn_probe(struct device *dev, struct regmap *regmap,
data->irq = irq;
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",
&data->orientation);
if (ret)
......@@ -984,6 +1007,7 @@ int bmc150_magn_remove(struct device *dev)
bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true);
mutex_unlock(&data->mutex);
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
return 0;
}
EXPORT_SYMBOL(bmc150_magn_remove);
......
......@@ -24,6 +24,7 @@ enum magn_3d_channel {
CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
CHANNEL_SCAN_INDEX_NORTH_MAGN,
CHANNEL_SCAN_INDEX_NORTH_TRUE,
CHANNEL_SCAN_INDEX_TIMESTAMP,
MAGN_3D_CHANNEL_MAX,
};
......@@ -47,6 +48,7 @@ struct magn_3d_state {
struct common_attributes magn_flux_attr;
struct common_attributes rot_attr;
s64 timestamp;
};
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_MAGN_NORTH,
HID_USAGE_SENSOR_ORIENT_TRUE_NORTH,
HID_USAGE_SENSOR_TIME_TIMESTAMP,
};
/* Channel definitions */
......@@ -124,7 +127,8 @@ static const struct iio_chan_spec magn_3d_channels[] = {
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
}
},
IIO_CHAN_SOFT_TIMESTAMP(7)
};
/* Adjust channel real bits based on report descriptor */
......@@ -273,13 +277,6 @@ static const struct iio_info magn_3d_info = {
.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 */
static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
......@@ -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);
dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
if (atomic_read(&magn_state->magn_flux_attributes.data_ready))
hid_sensor_push_data(indio_dev, magn_state->iio_vals);
if (atomic_read(&magn_state->magn_flux_attributes.data_ready)) {
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;
}
......@@ -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)
+ CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP;
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:
return -EINVAL;
}
......@@ -386,9 +395,10 @@ static int magn_3d_parse_report(struct platform_device *pdev,
return -ENOMEM;
}
st->iio_vals = devm_kcalloc(&pdev->dev, attr_count,
sizeof(u32),
GFP_KERNEL);
/* attr_count include timestamp channel, and the iio_vals should be aligned to 8byte */
st->iio_vals = devm_kcalloc(&pdev->dev,
((attr_count + 1) % 2 + (attr_count + 1) / 2) * 2,
sizeof(u32), GFP_KERNEL);
if (!st->iio_vals) {
dev_err(&pdev->dev,
"failed to allocate space for iio values array\n");
......@@ -404,11 +414,13 @@ static int magn_3d_parse_report(struct platform_device *pdev,
(_channels[*chan_count]).scan_index = *chan_count;
(_channels[*chan_count]).address = i;
/* Set magn_val_addr to iio value address */
st->magn_val_addr[i] = &(st->iio_vals[*chan_count]);
magn_3d_adjust_channel_bit_mask(_channels,
*chan_count,
st->magn[i].size);
if (i != CHANNEL_SCAN_INDEX_TIMESTAMP) {
/* Set magn_val_addr to iio value address */
st->magn_val_addr[i] = &st->iio_vals[*chan_count];
magn_3d_adjust_channel_bit_mask(_channels,
*chan_count,
st->magn[i].size);
}
(*chan_count)++;
}
}
......
This diff is collapsed.
......@@ -24,15 +24,21 @@ enum incl_3d_channel {
INCLI_3D_CHANNEL_MAX,
};
#define CHANNEL_SCAN_INDEX_TIMESTAMP INCLI_3D_CHANNEL_MAX
struct incl_3d_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
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_post_decml;
int scale_precision;
int value_offset;
s64 timestamp;
};
static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = {
......@@ -73,7 +79,8 @@ static const struct iio_chan_spec incl_3d_channels[] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
},
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP),
};
/* Adjust channel real bits based on report descriptor */
......@@ -178,13 +185,6 @@ static const struct iio_info incl_3d_info = {
.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 */
static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
......@@ -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);
dev_dbg(&indio_dev->dev, "incl_3d_proc_event\n");
if (atomic_read(&incl_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev,
(u8 *)incl_state->incl_val,
sizeof(incl_state->incl_val));
if (atomic_read(&incl_state->common_attributes.data_ready)) {
if (!incl_state->timestamp)
incl_state->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev,
&incl_state->scan,
incl_state->timestamp);
incl_state->timestamp = 0;
}
return 0;
}
......@@ -214,13 +220,18 @@ static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
switch (usage_id) {
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;
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;
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;
default:
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