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()
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmAKlDkRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FohMrw/+POQpOgJ1ZEEZpIXFxtYnOC8QAPQk6SFf
 syt+m+THauWQ6tcL2GRaE4QDvcBqWvGV+YKK0S9TaQ+L+4R2Lp/6XJ9Gp+EeB2z+
 tnggshWbox4expvnSmKEFysLoiYQ5xmCf+EsGNs8UdVVCYpK4jdut914ev4ZqaGY
 zy1aopGh0XHHtrrGzqhE6q+p5FG11Iewi3iuvq11jK5DrmwddyhempUqkGPGow/1
 JIgVDgGOHXka85L7z8uJ/6JQtVRUTyUehb8fXLEDH7htSHCt8B62OwN/rwPIRXRY
 JElbwetptpM753UUS0qoMGyqcEEoOI2Cr5BEJVfOfpWH2O/lVcF+XlbCiD3wQT48
 1DjHfts0jO8X/O+C4ZbglfGM/AZ2fRmZLFy7mObK+CixFwH5wXv0zhVsHNzK4Vzu
 e0fHbMtGgK8W0Gp9kQL0Ki+SJkpnI6Ilujl0jOrmGenmW4t1i6k51okGDpVJ8azd
 wUHh0gvLEK0T1d2Cq8GdU+pUGyxNqu3bOSXLrMjJ+f+UFYHDcFWxWLD1p8YG6h0f
 cS40NtDfCQOWTy476Kg/jXAG4yQrEKz0dm6m4PoqB1WKZPLrMzgCapPLJVLdU71c
 Y+kH2MHHbwHrRGqcn0FE9kTJO3RaWax10QcMgn3ZWTMqOIgpW4zRpr1rSREdLiND
 buScx7gBKPY=
 =GLx1
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Greg Kroah-Hartman 2021-01-22 11:07:30 +01:00
Родитель 3dba1da360 1994a922eb
Коммит 8598bb4c87
69 изменённых файлов: 3714 добавлений и 666 удалений

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

@ -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.

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

@ -0,0 +1,31 @@
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.

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

@ -1,13 +1,22 @@
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;
};
};
};

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

@ -0,0 +1,63 @@
# 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:

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

@ -1,45 +0,0 @@
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>;
};
};
};

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

@ -0,0 +1,70 @@
# 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>;
};
};
};
};
...

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

@ -1,67 +0,0 @@
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>;
};
};
};

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

@ -0,0 +1,104 @@
# 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

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

@ -0,0 +1,112 @@
# 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);
}

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

@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
@ -92,7 +93,12 @@ static const unsigned int XADC_ZYNQ_UNMASK_TIMEOUT = 500;
#define XADC_AXI_REG_GIER 0x5c
#define XADC_AXI_REG_IPISR 0x60
#define XADC_AXI_REG_IPIER 0x68
#define XADC_AXI_ADC_REG_OFFSET 0x200
/* 7 Series */
#define XADC_7S_AXI_ADC_REG_OFFSET 0x200
/* UltraScale */
#define XADC_US_AXI_ADC_REG_OFFSET 0x400
#define XADC_AXI_RESET_MAGIC 0xa
#define XADC_AXI_GIER_ENABLE BIT(31)
@ -447,6 +453,12 @@ static const struct xadc_ops xadc_zynq_ops = {
.get_dclk_rate = xadc_zynq_get_dclk_rate,
.interrupt_handler = xadc_zynq_interrupt_handler,
.update_alarm = xadc_zynq_update_alarm,
.type = XADC_TYPE_S7,
};
static const unsigned int xadc_axi_reg_offsets[] = {
[XADC_TYPE_S7] = XADC_7S_AXI_ADC_REG_OFFSET,
[XADC_TYPE_US] = XADC_US_AXI_ADC_REG_OFFSET,
};
static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
@ -454,7 +466,8 @@ static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
{
uint32_t val32;
xadc_read_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, &val32);
xadc_read_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4,
&val32);
*val = val32 & 0xffff;
return 0;
@ -463,7 +476,8 @@ static int xadc_axi_read_adc_reg(struct xadc *xadc, unsigned int reg,
static int xadc_axi_write_adc_reg(struct xadc *xadc, unsigned int reg,
uint16_t val)
{
xadc_write_reg(xadc, XADC_AXI_ADC_REG_OFFSET + reg * 4, val);
xadc_write_reg(xadc, xadc_axi_reg_offsets[xadc->ops->type] + reg * 4,
val);
return 0;
}
@ -541,7 +555,7 @@ static unsigned long xadc_axi_get_dclk(struct xadc *xadc)
return clk_get_rate(xadc->clk);
}
static const struct xadc_ops xadc_axi_ops = {
static const struct xadc_ops xadc_7s_axi_ops = {
.read = xadc_axi_read_adc_reg,
.write = xadc_axi_write_adc_reg,
.setup = xadc_axi_setup,
@ -549,6 +563,18 @@ static const struct xadc_ops xadc_axi_ops = {
.update_alarm = xadc_axi_update_alarm,
.interrupt_handler = xadc_axi_interrupt_handler,
.flags = XADC_FLAGS_BUFFERED,
.type = XADC_TYPE_S7,
};
static const struct xadc_ops xadc_us_axi_ops = {
.read = xadc_axi_read_adc_reg,
.write = xadc_axi_write_adc_reg,
.setup = xadc_axi_setup,
.get_dclk_rate = xadc_axi_get_dclk,
.update_alarm = xadc_axi_update_alarm,
.interrupt_handler = xadc_axi_interrupt_handler,
.flags = XADC_FLAGS_BUFFERED,
.type = XADC_TYPE_US,
};
static int _xadc_update_adc_reg(struct xadc *xadc, unsigned int reg,
@ -585,15 +611,22 @@ static int xadc_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *mask)
{
struct xadc *xadc = iio_priv(indio_dev);
unsigned int n;
size_t new_size, n;
void *data;
n = bitmap_weight(mask, indio_dev->masklength);
kfree(xadc->data);
xadc->data = kcalloc(n, sizeof(*xadc->data), GFP_KERNEL);
if (!xadc->data)
if (check_mul_overflow(n, sizeof(*xadc->data), &new_size))
return -ENOMEM;
data = devm_krealloc(indio_dev->dev.parent, xadc->data,
new_size, GFP_KERNEL);
if (!data)
return -ENOMEM;
memset(data, 0, new_size);
xadc->data = data;
return 0;
}
@ -705,11 +738,12 @@ static const struct iio_trigger_ops xadc_trigger_ops = {
static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev,
const char *name)
{
struct device *dev = indio_dev->dev.parent;
struct iio_trigger *trig;
int ret;
trig = iio_trigger_alloc("%s%d-%s", indio_dev->name,
indio_dev->id, name);
trig = devm_iio_trigger_alloc(dev, "%s%d-%s", indio_dev->name,
indio_dev->id, name);
if (trig == NULL)
return ERR_PTR(-ENOMEM);
@ -717,21 +751,26 @@ static struct iio_trigger *xadc_alloc_trigger(struct iio_dev *indio_dev,
trig->ops = &xadc_trigger_ops;
iio_trigger_set_drvdata(trig, iio_priv(indio_dev));
ret = iio_trigger_register(trig);
ret = devm_iio_trigger_register(dev, trig);
if (ret)
goto error_free_trig;
return ERR_PTR(ret);
return trig;
error_free_trig:
iio_trigger_free(trig);
return ERR_PTR(ret);
}
static int xadc_power_adc_b(struct xadc *xadc, unsigned int seq_mode)
{
uint16_t val;
/*
* As per datasheet the power-down bits are don't care in the
* UltraScale, but as per reality setting the power-down bit for the
* non-existing ADC-B powers down the main ADC, so just return and don't
* do anything.
*/
if (xadc->ops->type == XADC_TYPE_US)
return 0;
/* Powerdown the ADC-B when it is not needed. */
switch (seq_mode) {
case XADC_CONF1_SEQ_SIMULTANEOUS:
@ -751,6 +790,10 @@ static int xadc_get_seq_mode(struct xadc *xadc, unsigned long scan_mode)
{
unsigned int aux_scan_mode = scan_mode >> 16;
/* UltraScale has only one ADC and supports only continuous mode */
if (xadc->ops->type == XADC_TYPE_US)
return XADC_CONF1_SEQ_CONTINUOUS;
if (xadc->external_mux_mode == XADC_EXTERNAL_MUX_DUAL)
return XADC_CONF1_SEQ_SIMULTANEOUS;
@ -863,6 +906,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct xadc *xadc = iio_priv(indio_dev);
unsigned int bits = chan->scan_type.realbits;
uint16_t val16;
int ret;
@ -874,17 +918,17 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
val16 >>= 4;
val16 >>= chan->scan_type.shift;
if (chan->scan_type.sign == 'u')
*val = val16;
else
*val = sign_extend32(val16, 11);
*val = sign_extend32(val16, bits - 1);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
/* V = (val * 3.0) / 4096 */
/* V = (val * 3.0) / 2**bits */
switch (chan->address) {
case XADC_REG_VCCINT:
case XADC_REG_VCCAUX:
@ -900,19 +944,19 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
*val = 1000;
break;
}
*val2 = 12;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_TEMP:
/* Temp in C = (val * 503.975) / 4096 - 273.15 */
/* Temp in C = (val * 503.975) / 2**bits - 273.15 */
*val = 503975;
*val2 = 12;
*val2 = bits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
/* Only the temperature channel has an offset */
*val = -((273150 << 12) / 503975);
*val = -((273150 << bits) / 503975);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = xadc_read_samplerate(xadc);
@ -1001,7 +1045,7 @@ static const struct iio_event_spec xadc_voltage_events[] = {
},
};
#define XADC_CHAN_TEMP(_chan, _scan_index, _addr) { \
#define XADC_CHAN_TEMP(_chan, _scan_index, _addr, _bits) { \
.type = IIO_TEMP, \
.indexed = 1, \
.channel = (_chan), \
@ -1015,14 +1059,14 @@ static const struct iio_event_spec xadc_voltage_events[] = {
.scan_index = (_scan_index), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 4, \
.shift = 16 - (_bits), \
.endianness = IIO_CPU, \
}, \
}
#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) { \
#define XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, _bits, _ext, _alarm) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
@ -1035,41 +1079,82 @@ static const struct iio_event_spec xadc_voltage_events[] = {
.scan_index = (_scan_index), \
.scan_type = { \
.sign = ((_addr) == XADC_REG_VREFN) ? 's' : 'u', \
.realbits = 12, \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 4, \
.shift = 16 - (_bits), \
.endianness = IIO_CPU, \
}, \
.extend_name = _ext, \
}
static const struct iio_chan_spec xadc_channels[] = {
XADC_CHAN_TEMP(0, 8, XADC_REG_TEMP),
XADC_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
XADC_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
XADC_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
XADC_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
XADC_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
XADC_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true),
XADC_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
XADC_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
XADC_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
XADC_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
XADC_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
XADC_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
XADC_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
XADC_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
XADC_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
XADC_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
XADC_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
XADC_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
XADC_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
XADC_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
XADC_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
XADC_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
XADC_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
XADC_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
XADC_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
/* 7 Series */
#define XADC_7S_CHAN_TEMP(_chan, _scan_index, _addr) \
XADC_CHAN_TEMP(_chan, _scan_index, _addr, 12)
#define XADC_7S_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) \
XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, 12, _ext, _alarm)
static const struct iio_chan_spec xadc_7s_channels[] = {
XADC_7S_CHAN_TEMP(0, 8, XADC_REG_TEMP),
XADC_7S_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
XADC_7S_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
XADC_7S_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
XADC_7S_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpint", true),
XADC_7S_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpaux", true),
XADC_7S_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccoddr", true),
XADC_7S_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
XADC_7S_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
XADC_7S_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
XADC_7S_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
XADC_7S_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
XADC_7S_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
XADC_7S_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
XADC_7S_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
XADC_7S_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
XADC_7S_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
XADC_7S_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
XADC_7S_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
XADC_7S_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
XADC_7S_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
XADC_7S_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
XADC_7S_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
XADC_7S_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
XADC_7S_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
XADC_7S_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
};
/* UltraScale */
#define XADC_US_CHAN_TEMP(_chan, _scan_index, _addr) \
XADC_CHAN_TEMP(_chan, _scan_index, _addr, 10)
#define XADC_US_CHAN_VOLTAGE(_chan, _scan_index, _addr, _ext, _alarm) \
XADC_CHAN_VOLTAGE(_chan, _scan_index, _addr, 10, _ext, _alarm)
static const struct iio_chan_spec xadc_us_channels[] = {
XADC_US_CHAN_TEMP(0, 8, XADC_REG_TEMP),
XADC_US_CHAN_VOLTAGE(0, 9, XADC_REG_VCCINT, "vccint", true),
XADC_US_CHAN_VOLTAGE(1, 10, XADC_REG_VCCAUX, "vccaux", true),
XADC_US_CHAN_VOLTAGE(2, 14, XADC_REG_VCCBRAM, "vccbram", true),
XADC_US_CHAN_VOLTAGE(3, 5, XADC_REG_VCCPINT, "vccpsintlp", true),
XADC_US_CHAN_VOLTAGE(4, 6, XADC_REG_VCCPAUX, "vccpsintfp", true),
XADC_US_CHAN_VOLTAGE(5, 7, XADC_REG_VCCO_DDR, "vccpsaux", true),
XADC_US_CHAN_VOLTAGE(6, 12, XADC_REG_VREFP, "vrefp", false),
XADC_US_CHAN_VOLTAGE(7, 13, XADC_REG_VREFN, "vrefn", false),
XADC_US_CHAN_VOLTAGE(8, 11, XADC_REG_VPVN, NULL, false),
XADC_US_CHAN_VOLTAGE(9, 16, XADC_REG_VAUX(0), NULL, false),
XADC_US_CHAN_VOLTAGE(10, 17, XADC_REG_VAUX(1), NULL, false),
XADC_US_CHAN_VOLTAGE(11, 18, XADC_REG_VAUX(2), NULL, false),
XADC_US_CHAN_VOLTAGE(12, 19, XADC_REG_VAUX(3), NULL, false),
XADC_US_CHAN_VOLTAGE(13, 20, XADC_REG_VAUX(4), NULL, false),
XADC_US_CHAN_VOLTAGE(14, 21, XADC_REG_VAUX(5), NULL, false),
XADC_US_CHAN_VOLTAGE(15, 22, XADC_REG_VAUX(6), NULL, false),
XADC_US_CHAN_VOLTAGE(16, 23, XADC_REG_VAUX(7), NULL, false),
XADC_US_CHAN_VOLTAGE(17, 24, XADC_REG_VAUX(8), NULL, false),
XADC_US_CHAN_VOLTAGE(18, 25, XADC_REG_VAUX(9), NULL, false),
XADC_US_CHAN_VOLTAGE(19, 26, XADC_REG_VAUX(10), NULL, false),
XADC_US_CHAN_VOLTAGE(20, 27, XADC_REG_VAUX(11), NULL, false),
XADC_US_CHAN_VOLTAGE(21, 28, XADC_REG_VAUX(12), NULL, false),
XADC_US_CHAN_VOLTAGE(22, 29, XADC_REG_VAUX(13), NULL, false),
XADC_US_CHAN_VOLTAGE(23, 30, XADC_REG_VAUX(14), NULL, false),
XADC_US_CHAN_VOLTAGE(24, 31, XADC_REG_VAUX(15), NULL, false),
};
static const struct iio_info xadc_info = {
@ -1083,8 +1168,16 @@ static const struct iio_info xadc_info = {
};
static const struct of_device_id xadc_of_match_table[] = {
{ .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops },
{ .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops },
{
.compatible = "xlnx,zynq-xadc-1.00.a",
.data = &xadc_zynq_ops
}, {
.compatible = "xlnx,axi-xadc-1.00.a",
.data = &xadc_7s_axi_ops
}, {
.compatible = "xlnx,system-management-wiz-1.3",
.data = &xadc_us_axi_ops
},
{ },
};
MODULE_DEVICE_TABLE(of, xadc_of_match_table);
@ -1094,8 +1187,10 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
{
struct device *dev = indio_dev->dev.parent;
struct xadc *xadc = iio_priv(indio_dev);
const struct iio_chan_spec *channel_templates;
struct iio_chan_spec *channels, *chan;
struct device_node *chan_node, *child;
unsigned int max_channels;
unsigned int num_channels;
const char *external_mux;
u32 ext_mux_chan;
@ -1136,9 +1231,15 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
*conf |= XADC_CONF0_MUX | XADC_CONF0_CHAN(ext_mux_chan);
}
channels = devm_kmemdup(dev, xadc_channels,
sizeof(xadc_channels), GFP_KERNEL);
if (xadc->ops->type == XADC_TYPE_S7) {
channel_templates = xadc_7s_channels;
max_channels = ARRAY_SIZE(xadc_7s_channels);
} else {
channel_templates = xadc_us_channels;
max_channels = ARRAY_SIZE(xadc_us_channels);
}
channels = devm_kmemdup(dev, channel_templates,
sizeof(channels[0]) * max_channels, GFP_KERNEL);
if (!channels)
return -ENOMEM;
@ -1148,7 +1249,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
chan_node = of_get_child_by_name(np, "xlnx,channels");
if (chan_node) {
for_each_child_of_node(chan_node, child) {
if (num_channels >= ARRAY_SIZE(xadc_channels)) {
if (num_channels >= max_channels) {
of_node_put(child);
break;
}
@ -1184,8 +1285,28 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
return 0;
}
static const char * const xadc_type_names[] = {
[XADC_TYPE_S7] = "xadc",
[XADC_TYPE_US] = "xilinx-system-monitor",
};
static void xadc_clk_disable_unprepare(void *data)
{
struct clk *clk = data;
clk_disable_unprepare(clk);
}
static void xadc_cancel_delayed_work(void *data)
{
struct delayed_work *work = data;
cancel_delayed_work_sync(work);
}
static int xadc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *id;
struct iio_dev *indio_dev;
unsigned int bipolar_mask;
@ -1195,10 +1316,10 @@ static int xadc_probe(struct platform_device *pdev)
int irq;
int i;
if (!pdev->dev.of_node)
if (!dev->of_node)
return -ENODEV;
id = of_match_node(xadc_of_match_table, pdev->dev.of_node);
id = of_match_node(xadc_of_match_table, dev->of_node);
if (!id)
return -EINVAL;
@ -1206,7 +1327,7 @@ static int xadc_probe(struct platform_device *pdev)
if (irq <= 0)
return -ENXIO;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc));
indio_dev = devm_iio_device_alloc(dev, sizeof(*xadc));
if (!indio_dev)
return -ENOMEM;
@ -1222,43 +1343,44 @@ static int xadc_probe(struct platform_device *pdev)
if (IS_ERR(xadc->base))
return PTR_ERR(xadc->base);
indio_dev->name = "xadc";
indio_dev->name = xadc_type_names[xadc->ops->type];
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &xadc_info;
ret = xadc_parse_dt(indio_dev, pdev->dev.of_node, &conf0);
ret = xadc_parse_dt(indio_dev, dev->of_node, &conf0);
if (ret)
return ret;
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time, &xadc_trigger_handler,
&xadc_buffer_ops);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
&iio_pollfunc_store_time,
&xadc_trigger_handler,
&xadc_buffer_ops);
if (ret)
return ret;
xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst");
if (IS_ERR(xadc->convst_trigger)) {
ret = PTR_ERR(xadc->convst_trigger);
goto err_triggered_buffer_cleanup;
}
if (IS_ERR(xadc->convst_trigger))
return PTR_ERR(xadc->convst_trigger);
xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev,
"samplerate");
if (IS_ERR(xadc->samplerate_trigger)) {
ret = PTR_ERR(xadc->samplerate_trigger);
goto err_free_convst_trigger;
}
if (IS_ERR(xadc->samplerate_trigger))
return PTR_ERR(xadc->samplerate_trigger);
}
xadc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(xadc->clk)) {
ret = PTR_ERR(xadc->clk);
goto err_free_samplerate_trigger;
}
xadc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(xadc->clk))
return PTR_ERR(xadc->clk);
ret = clk_prepare_enable(xadc->clk);
if (ret)
goto err_free_samplerate_trigger;
return ret;
ret = devm_add_action_or_reset(dev,
xadc_clk_disable_unprepare, xadc->clk);
if (ret)
return ret;
/*
* Make sure not to exceed the maximum samplerate since otherwise the
@ -1267,22 +1389,28 @@ static int xadc_probe(struct platform_device *pdev)
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
ret = xadc_read_samplerate(xadc);
if (ret < 0)
goto err_free_samplerate_trigger;
return ret;
if (ret > XADC_MAX_SAMPLERATE) {
ret = xadc_write_samplerate(xadc, XADC_MAX_SAMPLERATE);
if (ret < 0)
goto err_free_samplerate_trigger;
return ret;
}
}
ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0,
dev_name(&pdev->dev), indio_dev);
ret = devm_request_irq(dev, xadc->irq, xadc->ops->interrupt_handler, 0,
dev_name(dev), indio_dev);
if (ret)
goto err_clk_disable_unprepare;
return ret;
ret = devm_add_action_or_reset(dev, xadc_cancel_delayed_work,
&xadc->zynq_unmask_work);
if (ret)
return ret;
ret = xadc->ops->setup(pdev, indio_dev, xadc->irq);
if (ret)
goto err_free_irq;
return ret;
for (i = 0; i < 16; i++)
xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i),
@ -1290,7 +1418,7 @@ static int xadc_probe(struct platform_device *pdev)
ret = xadc_write_adc_reg(xadc, XADC_REG_CONF0, conf0);
if (ret)
goto err_free_irq;
return ret;
bipolar_mask = 0;
for (i = 0; i < indio_dev->num_channels; i++) {
@ -1300,17 +1428,18 @@ static int xadc_probe(struct platform_device *pdev)
ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(0), bipolar_mask);
if (ret)
goto err_free_irq;
return ret;
ret = xadc_write_adc_reg(xadc, XADC_REG_INPUT_MODE(1),
bipolar_mask >> 16);
if (ret)
goto err_free_irq;
return ret;
/* Disable all alarms */
ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK,
XADC_CONF1_ALARM_MASK);
if (ret)
goto err_free_irq;
return ret;
/* Set thresholds to min/max */
for (i = 0; i < 16; i++) {
@ -1325,60 +1454,17 @@ static int xadc_probe(struct platform_device *pdev)
ret = xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
xadc->threshold[i]);
if (ret)
goto err_free_irq;
return ret;
}
/* Go to non-buffered mode */
xadc_postdisable(indio_dev);
ret = iio_device_register(indio_dev);
if (ret)
goto err_free_irq;
platform_set_drvdata(pdev, indio_dev);
return 0;
err_free_irq:
free_irq(xadc->irq, indio_dev);
cancel_delayed_work_sync(&xadc->zynq_unmask_work);
err_clk_disable_unprepare:
clk_disable_unprepare(xadc->clk);
err_free_samplerate_trigger:
if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
iio_trigger_free(xadc->samplerate_trigger);
err_free_convst_trigger:
if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
iio_trigger_free(xadc->convst_trigger);
err_triggered_buffer_cleanup:
if (xadc->ops->flags & XADC_FLAGS_BUFFERED)
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int xadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct xadc *xadc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
iio_trigger_free(xadc->samplerate_trigger);
iio_trigger_free(xadc->convst_trigger);
iio_triggered_buffer_cleanup(indio_dev);
}
free_irq(xadc->irq, indio_dev);
cancel_delayed_work_sync(&xadc->zynq_unmask_work);
clk_disable_unprepare(xadc->clk);
kfree(xadc->data);
return 0;
return devm_iio_device_register(dev, indio_dev);
}
static struct platform_driver xadc_driver = {
.probe = xadc_probe,
.remove = xadc_remove,
.driver = {
.name = "xadc",
.of_match_table = xadc_of_match_table,

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

@ -155,9 +155,6 @@ err_out:
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;
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)
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

643
drivers/iio/dac/ad5766.c Normal file
Просмотреть файл

@ -0,0 +1,643 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Analog Devices AD5766, AD5767
* Digital to Analog Converters driver
* Copyright 2019-2020 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <asm/unaligned.h>
#define AD5766_UPPER_WORD_SPI_MASK GENMASK(31, 16)
#define AD5766_LOWER_WORD_SPI_MASK GENMASK(15, 0)
#define AD5766_DITHER_SOURCE_MASK(ch) GENMASK(((2 * ch) + 1), (2 * ch))
#define AD5766_DITHER_SOURCE(ch, source) BIT((ch * 2) + source)
#define AD5766_DITHER_SCALE_MASK(x) AD5766_DITHER_SOURCE_MASK(x)
#define AD5766_DITHER_SCALE(ch, scale) (scale << (ch * 2))
#define AD5766_DITHER_ENABLE_MASK(ch) BIT(ch)
#define AD5766_DITHER_ENABLE(ch, state) ((!state) << ch)
#define AD5766_DITHER_INVERT_MASK(ch) BIT(ch)
#define AD5766_DITHER_INVERT(ch, state) (state << ch)
#define AD5766_CMD_NOP_MUX_OUT 0x00
#define AD5766_CMD_SDO_CNTRL 0x01
#define AD5766_CMD_WR_IN_REG(x) (0x10 | ((x) & GENMASK(3, 0)))
#define AD5766_CMD_WR_DAC_REG(x) (0x20 | ((x) & GENMASK(3, 0)))
#define AD5766_CMD_SW_LDAC 0x30
#define AD5766_CMD_SPAN_REG 0x40
#define AD5766_CMD_WR_PWR_DITHER 0x51
#define AD5766_CMD_WR_DAC_REG_ALL 0x60
#define AD5766_CMD_SW_FULL_RESET 0x70
#define AD5766_CMD_READBACK_REG(x) (0x80 | ((x) & GENMASK(3, 0)))
#define AD5766_CMD_DITHER_SIG_1 0x90
#define AD5766_CMD_DITHER_SIG_2 0xA0
#define AD5766_CMD_INV_DITHER 0xB0
#define AD5766_CMD_DITHER_SCALE_1 0xC0
#define AD5766_CMD_DITHER_SCALE_2 0xD0
#define AD5766_FULL_RESET_CODE 0x1234
enum ad5766_type {
ID_AD5766,
ID_AD5767,
};
enum ad5766_voltage_range {
AD5766_VOLTAGE_RANGE_M20V_0V,
AD5766_VOLTAGE_RANGE_M16V_to_0V,
AD5766_VOLTAGE_RANGE_M10V_to_0V,
AD5766_VOLTAGE_RANGE_M12V_to_14V,
AD5766_VOLTAGE_RANGE_M16V_to_10V,
AD5766_VOLTAGE_RANGE_M10V_to_6V,
AD5766_VOLTAGE_RANGE_M5V_to_5V,
AD5766_VOLTAGE_RANGE_M10V_to_10V,
};
/**
* struct ad5766_chip_info - chip specific information
* @num_channels: number of channels
* @channels: channel specification
*/
struct ad5766_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
};
enum {
AD5766_DITHER_ENABLE,
AD5766_DITHER_INVERT,
AD5766_DITHER_SOURCE,
};
/*
* Dither signal can also be scaled.
* Available dither scale strings corresponding to "dither_scale" field in
* "struct ad5766_state".
*/
static const char * const ad5766_dither_scales[] = {
"1",
"0.75",
"0.5",
"0.25",
};
/**
* struct ad5766_state - driver instance specific data
* @spi: SPI device
* @lock: Lock used to restrict concurent access to SPI device
* @chip_info: Chip model specific constants
* @gpio_reset: Reset GPIO, used to reset the device
* @crt_range: Current selected output range
* @dither_enable: Power enable bit for each channel dither block (for
* example, D15 = DAC 15,D8 = DAC 8, and D0 = DAC 0)
* 0 - Normal operation, 1 - Power down
* @dither_invert: Inverts the dither signal applied to the selected DAC
* outputs
* @dither_source: Selects between 2 possible sources:
* 1: N0, 2: N1
* Two bits are used for each channel
* @dither_scale: Two bits are used for each of the 16 channels:
* 0: 1 SCALING, 1: 0.75 SCALING, 2: 0.5 SCALING,
* 3: 0.25 SCALING.
* @data: SPI transfer buffers
*/
struct ad5766_state {
struct spi_device *spi;
struct mutex lock;
const struct ad5766_chip_info *chip_info;
struct gpio_desc *gpio_reset;
enum ad5766_voltage_range crt_range;
u16 dither_enable;
u16 dither_invert;
u32 dither_source;
u32 dither_scale;
union {
u32 d32;
u16 w16[2];
u8 b8[4];
} data[3] ____cacheline_aligned;
};
struct ad5766_span_tbl {
int min;
int max;
};
static const struct ad5766_span_tbl ad5766_span_tbl[] = {
[AD5766_VOLTAGE_RANGE_M20V_0V] = {-20, 0},
[AD5766_VOLTAGE_RANGE_M16V_to_0V] = {-16, 0},
[AD5766_VOLTAGE_RANGE_M10V_to_0V] = {-10, 0},
[AD5766_VOLTAGE_RANGE_M12V_to_14V] = {-12, 14},
[AD5766_VOLTAGE_RANGE_M16V_to_10V] = {-16, 10},
[AD5766_VOLTAGE_RANGE_M10V_to_6V] = {-10, 6},
[AD5766_VOLTAGE_RANGE_M5V_to_5V] = {-5, 5},
[AD5766_VOLTAGE_RANGE_M10V_to_10V] = {-10, 10},
};
static int __ad5766_spi_read(struct ad5766_state *st, u8 dac, int *val)
{
int ret;
struct spi_transfer xfers[] = {
{
.tx_buf = &st->data[0].d32,
.bits_per_word = 8,
.len = 3,
.cs_change = 1,
}, {
.tx_buf = &st->data[1].d32,
.rx_buf = &st->data[2].d32,
.bits_per_word = 8,
.len = 3,
},
};
st->data[0].d32 = AD5766_CMD_READBACK_REG(dac);
st->data[1].d32 = AD5766_CMD_NOP_MUX_OUT;
ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
if (ret)
return ret;
*val = st->data[2].w16[1];
return ret;
}
static int __ad5766_spi_write(struct ad5766_state *st, u8 command, u16 data)
{
st->data[0].b8[0] = command;
put_unaligned_be16(data, &st->data[0].b8[1]);
return spi_write(st->spi, &st->data[0].b8[0], 3);
}
static int ad5766_read(struct iio_dev *indio_dev, u8 dac, int *val)
{
struct ad5766_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->lock);
ret = __ad5766_spi_read(st, dac, val);
mutex_unlock(&st->lock);
return ret;
}
static int ad5766_write(struct iio_dev *indio_dev, u8 dac, u16 data)
{
struct ad5766_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->lock);
ret = __ad5766_spi_write(st, AD5766_CMD_WR_DAC_REG(dac), data);
mutex_unlock(&st->lock);
return ret;
}
static int ad5766_reset(struct ad5766_state *st)
{
int ret;
if (st->gpio_reset) {
gpiod_set_value_cansleep(st->gpio_reset, 1);
ndelay(100); /* t_reset >= 100ns */
gpiod_set_value_cansleep(st->gpio_reset, 0);
} else {
ret = __ad5766_spi_write(st, AD5766_CMD_SW_FULL_RESET,
AD5766_FULL_RESET_CODE);
if (ret < 0)
return ret;
}
/*
* Minimum time between a reset and the subsequent successful write is
* typically 25 ns
*/
ndelay(25);
return 0;
}
static int ad5766_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ad5766_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ad5766_read(indio_dev, chan->address, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = ad5766_span_tbl[st->crt_range].min;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = ad5766_span_tbl[st->crt_range].max -
ad5766_span_tbl[st->crt_range].min;
*val2 = st->chip_info->channels[0].scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static int ad5766_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long info)
{
switch (info) {
case IIO_CHAN_INFO_RAW:
{
const int max_val = GENMASK(chan->scan_type.realbits - 1, 0);
if (val > max_val || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
return ad5766_write(indio_dev, chan->address, val);
}
default:
return -EINVAL;
}
}
static const struct iio_info ad5766_info = {
.read_raw = ad5766_read_raw,
.write_raw = ad5766_write_raw,
};
static int ad5766_get_dither_source(struct iio_dev *dev,
const struct iio_chan_spec *chan)
{
struct ad5766_state *st = iio_priv(dev);
u32 source;
source = st->dither_source & AD5766_DITHER_SOURCE_MASK(chan->channel);
source = source >> (chan->channel * 2);
source -= 1;
return source;
}
static int ad5766_set_dither_source(struct iio_dev *dev,
const struct iio_chan_spec *chan,
unsigned int source)
{
struct ad5766_state *st = iio_priv(dev);
uint16_t val;
int ret;
st->dither_source &= ~AD5766_DITHER_SOURCE_MASK(chan->channel);
st->dither_source |= AD5766_DITHER_SOURCE(chan->channel, source);
val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_source);
ret = ad5766_write(dev, AD5766_CMD_DITHER_SIG_1, val);
if (ret)
return ret;
val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_source);
return ad5766_write(dev, AD5766_CMD_DITHER_SIG_2, val);
}
static int ad5766_get_dither_scale(struct iio_dev *dev,
const struct iio_chan_spec *chan)
{
struct ad5766_state *st = iio_priv(dev);
u32 scale;
scale = st->dither_scale & AD5766_DITHER_SCALE_MASK(chan->channel);
return (scale >> (chan->channel * 2));
}
static int ad5766_set_dither_scale(struct iio_dev *dev,
const struct iio_chan_spec *chan,
unsigned int scale)
{
int ret;
struct ad5766_state *st = iio_priv(dev);
uint16_t val;
st->dither_scale &= ~AD5766_DITHER_SCALE_MASK(chan->channel);
st->dither_scale |= AD5766_DITHER_SCALE(chan->channel, scale);
val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_scale);
ret = ad5766_write(dev, AD5766_CMD_DITHER_SCALE_1, val);
if (ret)
return ret;
val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_scale);
return ad5766_write(dev, AD5766_CMD_DITHER_SCALE_2, val);
}
static const struct iio_enum ad5766_dither_scale_enum = {
.items = ad5766_dither_scales,
.num_items = ARRAY_SIZE(ad5766_dither_scales),
.set = ad5766_set_dither_scale,
.get = ad5766_get_dither_scale,
};
static ssize_t ad5766_read_ext(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct ad5766_state *st = iio_priv(indio_dev);
switch (private) {
case AD5766_DITHER_ENABLE:
return sprintf(buf, "%u\n",
!(st->dither_enable & BIT(chan->channel)));
break;
case AD5766_DITHER_INVERT:
return sprintf(buf, "%u\n",
!!(st->dither_invert & BIT(chan->channel)));
break;
case AD5766_DITHER_SOURCE:
return sprintf(buf, "%d\n",
ad5766_get_dither_source(indio_dev, chan));
default:
return -EINVAL;
}
}
static ssize_t ad5766_write_ext(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct ad5766_state *st = iio_priv(indio_dev);
bool readin;
int ret;
ret = kstrtobool(buf, &readin);
if (ret)
return ret;
switch (private) {
case AD5766_DITHER_ENABLE:
st->dither_enable &= ~AD5766_DITHER_ENABLE_MASK(chan->channel);
st->dither_enable |= AD5766_DITHER_ENABLE(chan->channel,
readin);
ret = ad5766_write(indio_dev, AD5766_CMD_WR_PWR_DITHER,
st->dither_enable);
break;
case AD5766_DITHER_INVERT:
st->dither_invert &= ~AD5766_DITHER_INVERT_MASK(chan->channel);
st->dither_invert |= AD5766_DITHER_INVERT(chan->channel,
readin);
ret = ad5766_write(indio_dev, AD5766_CMD_INV_DITHER,
st->dither_invert);
break;
case AD5766_DITHER_SOURCE:
ret = ad5766_set_dither_source(indio_dev, chan, readin);
break;
default:
return -EINVAL;
}
return ret ? ret : len;
}
#define _AD5766_CHAN_EXT_INFO(_name, _what, _shared) { \
.name = _name, \
.read = ad5766_read_ext, \
.write = ad5766_write_ext, \
.private = _what, \
.shared = _shared, \
}
#define IIO_ENUM_AVAILABLE_SHARED(_name, _shared, _e) \
{ \
.name = (_name "_available"), \
.shared = _shared, \
.read = iio_enum_available_read, \
.private = (uintptr_t)(_e), \
}
static const struct iio_chan_spec_ext_info ad5766_ext_info[] = {
_AD5766_CHAN_EXT_INFO("dither_enable", AD5766_DITHER_ENABLE,
IIO_SEPARATE),
_AD5766_CHAN_EXT_INFO("dither_invert", AD5766_DITHER_INVERT,
IIO_SEPARATE),
_AD5766_CHAN_EXT_INFO("dither_source", AD5766_DITHER_SOURCE,
IIO_SEPARATE),
IIO_ENUM("dither_scale", IIO_SEPARATE, &ad5766_dither_scale_enum),
IIO_ENUM_AVAILABLE_SHARED("dither_scale",
IIO_SEPARATE,
&ad5766_dither_scale_enum),
{}
};
#define AD576x_CHANNEL(_chan, _bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
.address = (_chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | \
BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (_bits), \
.storagebits = 16, \
.shift = 16 - (_bits), \
}, \
.ext_info = ad5766_ext_info, \
}
#define DECLARE_AD576x_CHANNELS(_name, _bits) \
const struct iio_chan_spec _name[] = { \
AD576x_CHANNEL(0, (_bits)), \
AD576x_CHANNEL(1, (_bits)), \
AD576x_CHANNEL(2, (_bits)), \
AD576x_CHANNEL(3, (_bits)), \
AD576x_CHANNEL(4, (_bits)), \
AD576x_CHANNEL(5, (_bits)), \
AD576x_CHANNEL(6, (_bits)), \
AD576x_CHANNEL(7, (_bits)), \
AD576x_CHANNEL(8, (_bits)), \
AD576x_CHANNEL(9, (_bits)), \
AD576x_CHANNEL(10, (_bits)), \
AD576x_CHANNEL(11, (_bits)), \
AD576x_CHANNEL(12, (_bits)), \
AD576x_CHANNEL(13, (_bits)), \
AD576x_CHANNEL(14, (_bits)), \
AD576x_CHANNEL(15, (_bits)), \
}
static DECLARE_AD576x_CHANNELS(ad5766_channels, 16);
static DECLARE_AD576x_CHANNELS(ad5767_channels, 12);
static const struct ad5766_chip_info ad5766_chip_infos[] = {
[ID_AD5766] = {
.num_channels = ARRAY_SIZE(ad5766_channels),
.channels = ad5766_channels,
},
[ID_AD5767] = {
.num_channels = ARRAY_SIZE(ad5767_channels),
.channels = ad5767_channels,
},
};
static int ad5766_get_output_range(struct ad5766_state *st)
{
int i, ret, min, max, tmp[2];
ret = device_property_read_u32_array(&st->spi->dev,
"output-range-voltage",
tmp, 2);
if (ret)
return ret;
min = tmp[0] / 1000;
max = tmp[1] / 1000;
for (i = 0; i < ARRAY_SIZE(ad5766_span_tbl); i++) {
if (ad5766_span_tbl[i].min != min ||
ad5766_span_tbl[i].max != max)
continue;
st->crt_range = i;
return 0;
}
return -EINVAL;
}
static int ad5766_default_setup(struct ad5766_state *st)
{
uint16_t val;
int ret, i;
/* Always issue a reset before writing to the span register. */
ret = ad5766_reset(st);
if (ret)
return ret;
ret = ad5766_get_output_range(st);
if (ret)
return ret;
/* Dither power down */
st->dither_enable = GENMASK(15, 0);
ret = __ad5766_spi_write(st, AD5766_CMD_WR_PWR_DITHER,
st->dither_enable);
if (ret)
return ret;
st->dither_source = 0;
for (i = 0; i < ARRAY_SIZE(ad5766_channels); i++)
st->dither_source |= AD5766_DITHER_SOURCE(i, 0);
val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_source);
ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SIG_1, val);
if (ret)
return ret;
val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_source);
ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SIG_2, val);
if (ret)
return ret;
st->dither_scale = 0;
val = FIELD_GET(AD5766_LOWER_WORD_SPI_MASK, st->dither_scale);
ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SCALE_1, val);
if (ret)
return ret;
val = FIELD_GET(AD5766_UPPER_WORD_SPI_MASK, st->dither_scale);
ret = __ad5766_spi_write(st, AD5766_CMD_DITHER_SCALE_2, val);
if (ret)
return ret;
st->dither_invert = 0;
ret = __ad5766_spi_write(st, AD5766_CMD_INV_DITHER, st->dither_invert);
if (ret)
return ret;
return __ad5766_spi_write(st, AD5766_CMD_SPAN_REG, st->crt_range);
}
static int ad5766_probe(struct spi_device *spi)
{
enum ad5766_type type;
struct iio_dev *indio_dev;
struct ad5766_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->spi = spi;
type = spi_get_device_id(spi)->driver_data;
st->chip_info = &ad5766_chip_infos[type];
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = &ad5766_info;
indio_dev->dev.parent = &spi->dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_reset))
return PTR_ERR(st->gpio_reset);
ret = ad5766_default_setup(st);
if (ret)
return ret;
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct of_device_id ad5766_dt_match[] = {
{ .compatible = "adi,ad5766" },
{ .compatible = "adi,ad5767" },
{}
};
MODULE_DEVICE_TABLE(of, ad5766_dt_match);
static const struct spi_device_id ad5766_spi_ids[] = {
{ "ad5766", ID_AD5766 },
{ "ad5767", ID_AD5767 },
{}
};
MODULE_DEVICE_TABLE(spi, ad5766_spi_ids);
static struct spi_driver ad5766_driver = {
.driver = {
.name = "ad5766",
.of_match_table = ad5766_dt_match,
},
.probe = ad5766_probe,
.id_table = ad5766_spi_ids,
};
module_spi_driver(ad5766_driver);
MODULE_AUTHOR("Denis-Gabriel Gheorghescu <denis.gheorghescu@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5766/AD5767 DACs");
MODULE_LICENSE("GPL v2");

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

@ -582,8 +582,7 @@ error_disable_reg:
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 @@ err_free_channel:
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 @@ error_free_chans:
#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)++;
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -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;

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

@ -20,11 +20,15 @@ struct dev_rot_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info quaternion;
u32 sampled_vals[4];
struct {
u32 sampled_vals[4] __aligned(16);
u64 timestamp __aligned(8);
} scan;
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
s64 timestamp;
};
/* Channel definitions */
@ -37,8 +41,10 @@ static const struct iio_chan_spec dev_rot_channels[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_HYSTERESIS)
}
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = 0
},
IIO_CHAN_SOFT_TIMESTAMP(1)
};
/* Adjust channel real bits based on report descriptor */
@ -70,7 +76,7 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
if (size >= 4) {
for (i = 0; i < 4; ++i)
vals[i] = rot_state->sampled_vals[i];
vals[i] = rot_state->scan.sampled_vals[i];
ret_type = IIO_VAL_INT_MULTIPLE;
*val_len = 4;
} else
@ -132,15 +138,6 @@ static const struct iio_info dev_rot_info = {
.write_raw = &dev_rot_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);
dev_dbg(&indio_dev->dev, "hid_sensor_push_data <<\n");
}
/* Callback handler to send event after all samples are received and captured */
static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned usage_id,
@ -150,10 +147,15 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
struct dev_rot_state *rot_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "dev_rot_proc_event\n");
if (atomic_read(&rot_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev,
(u8 *)rot_state->sampled_vals,
sizeof(rot_state->sampled_vals));
if (atomic_read(&rot_state->common_attributes.data_ready)) {
if (!rot_state->timestamp)
rot_state->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev, &rot_state->scan,
rot_state->timestamp);
rot_state->timestamp = 0;
}
return 0;
}
@ -168,10 +170,14 @@ static int dev_rot_capture_sample(struct hid_sensor_hub_device *hsdev,
struct dev_rot_state *rot_state = iio_priv(indio_dev);
if (usage_id == HID_USAGE_SENSOR_ORIENT_QUATERNION) {
memcpy(rot_state->sampled_vals, raw_data,
sizeof(rot_state->sampled_vals));
memcpy(&rot_state->scan.sampled_vals, raw_data,
sizeof(rot_state->scan.sampled_vals));
dev_dbg(&indio_dev->dev, "Recd Quat len:%zu::%zu\n", raw_len,
sizeof(rot_state->sampled_vals));
sizeof(rot_state->scan.sampled_vals));
} else if (usage_id == HID_USAGE_SENSOR_TIME_TIMESTAMP) {
rot_state->timestamp = hid_sensor_convert_timestamp(&rot_state->common_attributes,
*(s64 *)raw_data);
}
return 0;

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

@ -16,4 +16,20 @@ config IQS624_POS
To compile this driver as a module, choose M here: the module
will be called iqs624-pos.
config HID_SENSOR_CUSTOM_INTEL_HINGE
depends on HID_SENSOR_HUB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select HID_SENSOR_IIO_COMMON
select HID_SENSOR_IIO_TRIGGER
tristate "HID Hinge"
help
This sensor present three angles, hinge angel, screen angles
and keyboard angle respect to horizon (ground).
Say yes here to build support for the HID custom
intel hinge sensor.
To compile this driver as a module, choose M here: the
module will be called hid-sensor-custom-hinge.
endmenu

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

@ -4,4 +4,5 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE) += hid-sensor-custom-intel-hinge.o
obj-$(CONFIG_IQS624_POS) += iqs624-pos.o

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

@ -0,0 +1,385 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* HID Sensors Driver
* Copyright (c) 2020, Intel Corporation.
*/
#include <linux/hid-sensor-hub.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/platform_device.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
enum hinge_channel {
CHANNEL_SCAN_INDEX_HINGE_ANGLE,
CHANNEL_SCAN_INDEX_SCREEN_ANGLE,
CHANNEL_SCAN_INDEX_KEYBOARD_ANGLE,
CHANNEL_SCAN_INDEX_MAX,
};
#define CHANNEL_SCAN_INDEX_TIMESTAMP CHANNEL_SCAN_INDEX_MAX
static const u32 hinge_addresses[CHANNEL_SCAN_INDEX_MAX] = {
HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1),
HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(2),
HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(3)
};
static const char *const hinge_labels[CHANNEL_SCAN_INDEX_MAX] = { "hinge",
"screen",
"keyboard" };
struct hinge_state {
struct iio_dev *indio_dev;
struct hid_sensor_hub_attribute_info hinge[CHANNEL_SCAN_INDEX_MAX];
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
const char *labels[CHANNEL_SCAN_INDEX_MAX];
struct {
u32 hinge_val[3];
u64 timestamp __aligned(8);
} scan;
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
u64 timestamp;
};
/* Channel definitions */
static const struct iio_chan_spec hinge_channels[] = {
{
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_HINGE_ANGLE,
.scan_type = {
.sign = 's',
.storagebits = 32,
},
}, {
.type = IIO_ANGL,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_SCREEN_ANGLE,
.scan_type = {
.sign = 's',
.storagebits = 32,
},
}, {
.type = IIO_ANGL,
.indexed = 1,
.channel = 2,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_KEYBOARD_ANGLE,
.scan_type = {
.sign = 's',
.storagebits = 32,
},
},
IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
};
/* Adjust channel real bits based on report descriptor */
static void hinge_adjust_channel_realbits(struct iio_chan_spec *channels,
int channel, int size)
{
channels[channel].scan_type.realbits = size * 8;
}
/* Channel read_raw handler */
static int hinge_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
{
struct hinge_state *st = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev;
int report_id;
s32 min;
hsdev = st->common_attributes.hsdev;
switch (mask) {
case IIO_CHAN_INFO_RAW:
hid_sensor_power_state(&st->common_attributes, true);
report_id = st->hinge[chan->scan_index].report_id;
min = st->hinge[chan->scan_index].logical_minimum;
if (report_id < 0) {
hid_sensor_power_state(&st->common_attributes, false);
return -EINVAL;
}
*val = sensor_hub_input_attr_get_raw_value(st->common_attributes.hsdev,
hsdev->usage,
hinge_addresses[chan->scan_index],
report_id,
SENSOR_HUB_SYNC, min < 0);
hid_sensor_power_state(&st->common_attributes, false);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->scale_pre_decml;
*val2 = st->scale_post_decml;
return st->scale_precision;
case IIO_CHAN_INFO_OFFSET:
*val = st->value_offset;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
return hid_sensor_read_samp_freq_value(&st->common_attributes,
val, val2);
case IIO_CHAN_INFO_HYSTERESIS:
return hid_sensor_read_raw_hyst_value(&st->common_attributes,
val, val2);
default:
return -EINVAL;
}
}
/* Channel write_raw handler */
static int hinge_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct hinge_state *st = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
return hid_sensor_write_samp_freq_value(&st->common_attributes,
val, val2);
case IIO_CHAN_INFO_HYSTERESIS:
return hid_sensor_write_raw_hyst_value(&st->common_attributes,
val, val2);
default:
return -EINVAL;
}
}
static int hinge_read_label(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, char *label)
{
struct hinge_state *st = iio_priv(indio_dev);
return sprintf(label, "%s\n", st->labels[chan->channel]);
}
static const struct iio_info hinge_info = {
.read_raw = hinge_read_raw,
.write_raw = hinge_write_raw,
.read_label = hinge_read_label,
};
/*
* Callback handler to send event after all samples are received
* and captured.
*/
static int hinge_proc_event(struct hid_sensor_hub_device *hsdev,
unsigned int usage_id, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct hinge_state *st = iio_priv(indio_dev);
if (atomic_read(&st->common_attributes.data_ready)) {
if (!st->timestamp)
st->timestamp = iio_get_time_ns(indio_dev);
iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
st->timestamp);
st->timestamp = 0;
}
return 0;
}
/* Capture samples in local storage */
static int hinge_capture_sample(struct hid_sensor_hub_device *hsdev,
unsigned int usage_id, size_t raw_len,
char *raw_data, void *priv)
{
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct hinge_state *st = iio_priv(indio_dev);
int offset;
switch (usage_id) {
case HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1):
case HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(2):
case HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(3):
offset = usage_id - HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1);
st->scan.hinge_val[offset] = *(u32 *)raw_data;
return 0;
case HID_USAGE_SENSOR_TIME_TIMESTAMP:
st->timestamp = hid_sensor_convert_timestamp(&st->common_attributes,
*(int64_t *)raw_data);
return 0;
default:
return -EINVAL;
}
}
/* Parse report which is specific to an usage id */
static int hinge_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels,
unsigned int usage_id, struct hinge_state *st)
{
int ret;
int i;
for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; ++i) {
ret = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT,
usage_id,
hinge_addresses[i],
&st->hinge[i]);
if (ret < 0)
return ret;
hinge_adjust_channel_realbits(channels, i, st->hinge[i].size);
}
st->scale_precision = hid_sensor_format_scale(HID_USAGE_SENSOR_HINGE,
&st->hinge[CHANNEL_SCAN_INDEX_HINGE_ANGLE],
&st->scale_pre_decml, &st->scale_post_decml);
/* Set Sensitivity field ids, when there is no individual modifier */
if (st->common_attributes.sensitivity.index < 0) {
sensor_hub_input_get_attribute_info(hsdev,
HID_FEATURE_REPORT, usage_id,
HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(1),
&st->common_attributes.sensitivity);
dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
st->common_attributes.sensitivity.index,
st->common_attributes.sensitivity.report_id);
}
return ret;
}
/* Function to initialize the processing for usage id */
static int hid_hinge_probe(struct platform_device *pdev)
{
struct hinge_state *st;
struct iio_dev *indio_dev;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
int ret;
int i;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
st = iio_priv(indio_dev);
st->common_attributes.hsdev = hsdev;
st->common_attributes.pdev = pdev;
st->indio_dev = indio_dev;
for (i = 0; i < CHANNEL_SCAN_INDEX_MAX; i++)
st->labels[i] = hinge_labels[i];
ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
&st->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
}
indio_dev->num_channels = ARRAY_SIZE(hinge_channels);
indio_dev->channels = devm_kmemdup(&indio_dev->dev, hinge_channels,
sizeof(hinge_channels), GFP_KERNEL);
if (!indio_dev->channels)
return -ENOMEM;
ret = hinge_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
hsdev->usage, st);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
}
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &hinge_info;
indio_dev->name = "hinge";
indio_dev->modes = INDIO_DIRECT_MODE;
atomic_set(&st->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, indio_dev->name,
&st->common_attributes);
if (ret < 0) {
dev_err(&pdev->dev, "trigger setup failed\n");
return ret;
}
st->callbacks.send_event = hinge_proc_event;
st->callbacks.capture_sample = hinge_capture_sample;
st->callbacks.pdev = pdev;
ret = sensor_hub_register_callback(hsdev, hsdev->usage, &st->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
goto error_remove_trigger;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "device register failed\n");
goto error_remove_callback;
}
return ret;
error_remove_callback:
sensor_hub_remove_callback(hsdev, hsdev->usage);
error_remove_trigger:
hid_sensor_remove_trigger(indio_dev, &st->common_attributes);
return ret;
}
/* Function to deinitialize the processing for usage id */
static int hid_hinge_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hinge_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
sensor_hub_remove_callback(hsdev, hsdev->usage);
hid_sensor_remove_trigger(indio_dev, &st->common_attributes);
return 0;
}
static const struct platform_device_id hid_hinge_ids[] = {
{
/* Format: HID-SENSOR-INT-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-INT-020b",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, hid_hinge_ids);
static struct platform_driver hid_hinge_platform_driver = {
.id_table = hid_hinge_ids,
.driver = {
.name = KBUILD_MODNAME,
.pm = &hid_sensor_pm_ops,
},
.probe = hid_hinge_probe,
.remove = hid_hinge_remove,
};
module_platform_driver(hid_hinge_platform_driver);
MODULE_DESCRIPTION("HID Sensor INTEL Hinge");
MODULE_AUTHOR("Ye Xiang <xiang.ye@intel.com>");
MODULE_LICENSE("GPL");

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

@ -30,9 +30,25 @@
#include "../common/ms_sensors/ms_sensors_i2c.h"
struct ms_tp_data {
const char *name;
const struct ms_tp_hw_data *hw;
};
static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 };
/* String copy of the above const for readability purpose */
static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30";
static ssize_t ms5637_show_samp_freq(struct device *dev, struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ms_tp_dev *dev_data = iio_priv(indio_dev);
int i, len = 0;
for (i = 0; i <= dev_data->hw->max_res_index; i++)
len += sysfs_emit_at(buf, len, "%u ", ms5637_samp_freq[i]);
sysfs_emit_at(buf, len - 1, "\n");
return len;
}
static int ms5637_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
@ -109,10 +125,10 @@ static const struct iio_chan_spec ms5637_channels[] = {
}
};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq);
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq);
static struct attribute *ms5637_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
@ -129,6 +145,7 @@ static const struct iio_info ms5637_info = {
static int ms5637_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct ms_tp_data *data;
struct ms_tp_dev *dev_data;
struct iio_dev *indio_dev;
int ret;
@ -142,17 +159,25 @@ static int ms5637_probe(struct i2c_client *client,
return -EOPNOTSUPP;
}
if (id)
data = (const struct ms_tp_data *)id->driver_data;
else
data = device_get_match_data(&client->dev);
if (!data)
return -EINVAL;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
if (!indio_dev)
return -ENOMEM;
dev_data = iio_priv(indio_dev);
dev_data->client = client;
dev_data->res_index = 5;
dev_data->res_index = data->hw->max_res_index;
dev_data->hw = data->hw;
mutex_init(&dev_data->lock);
indio_dev->info = &ms5637_info;
indio_dev->name = id->name;
indio_dev->name = data->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ms5637_channels;
indio_dev->num_channels = ARRAY_SIZE(ms5637_channels);
@ -170,20 +195,44 @@ static int ms5637_probe(struct i2c_client *client,
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct ms_tp_hw_data ms5637_hw_data = {
.prom_len = 7,
.max_res_index = 5
};
static const struct ms_tp_hw_data ms5803_hw_data = {
.prom_len = 8,
.max_res_index = 4
};
static const struct ms_tp_data ms5637_data = { .name = "ms5637", .hw = &ms5637_hw_data };
static const struct ms_tp_data ms5803_data = { .name = "ms5803", .hw = &ms5803_hw_data };
static const struct ms_tp_data ms5805_data = { .name = "ms5805", .hw = &ms5637_hw_data };
static const struct ms_tp_data ms5837_data = { .name = "ms5837", .hw = &ms5637_hw_data };
static const struct ms_tp_data ms8607_data = {
.name = "ms8607-temppressure",
.hw = &ms5637_hw_data,
};
static const struct i2c_device_id ms5637_id[] = {
{"ms5637", 0},
{"ms5805", 0},
{"ms5837", 0},
{"ms8607-temppressure", 0},
{"ms5637", (kernel_ulong_t)&ms5637_data },
{"ms5805", (kernel_ulong_t)&ms5805_data },
{"ms5837", (kernel_ulong_t)&ms5837_data },
{"ms8607-temppressure", (kernel_ulong_t)&ms8607_data },
{}
};
MODULE_DEVICE_TABLE(i2c, ms5637_id);
static const struct of_device_id ms5637_of_match[] = {
{ .compatible = "meas,ms5637", },
{ .compatible = "meas,ms5805", },
{ .compatible = "meas,ms5837", },
{ .compatible = "meas,ms8607-temppressure", },
{ .compatible = "meas,ms5637", .data = &ms5637_data },
{ .compatible = "meas,ms5803", .data = &ms5803_data },
{ .compatible = "meas,ms5805", .data = &ms5805_data },
{ .compatible = "meas,ms5837", .data = &ms5837_data },
{ .compatible = "meas,ms8607-temppressure", .data = &ms8607_data },
{ },
};
MODULE_DEVICE_TABLE(of, ms5637_of_match);

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

@ -141,4 +141,23 @@ static inline s32 fixp_sin32_rad(u32 radians, u32 twopi)
#define fixp_cos32_rad(rad, twopi) \
fixp_sin32_rad(rad + twopi / 4, twopi)
/**
* fixp_linear_interpolate() - interpolates a value from two known points
*
* @x0: x value of point 0
* @y0: y value of point 0
* @x1: x value of point 1
* @y1: y value of point 1
* @x: the linear interpolant
*/
static inline int fixp_linear_interpolate(int x0, int y0, int x1, int y1, int x)
{
if (y0 == y1 || x == x0)
return y0;
if (x1 == x0 || x == x1)
return y1;
return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
}
#endif

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

@ -128,6 +128,10 @@
#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND 0x15
/* Common selectors */
#define HID_USAGE_SENSOR_PROP_DESC 0x200300
#define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301
#define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307
#define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305
#define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E
#define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F
#define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310
@ -158,4 +162,14 @@
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x200840
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x200841
/* Custom Sensor (2000e1) */
#define HID_USAGE_SENSOR_HINGE 0x20020B
#define HID_USAGE_SENSOR_DATA_FIELD_LOCATION 0x200400
#define HID_USAGE_SENSOR_DATA_FIELE_TIME_SINCE_SYS_BOOT 0x20052B
#define HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_USAGE 0x200541
#define HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE_BASE 0x200543
/* Custom Sensor data 28=>x>=0 */
#define HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(x) \
(HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE_BASE + (x))
#endif

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

@ -6,6 +6,8 @@
#ifndef QCOM_VADC_COMMON_H
#define QCOM_VADC_COMMON_H
#include <linux/types.h>
#define VADC_CONV_TIME_MIN_US 2000
#define VADC_CONV_TIME_MAX_US 2100
@ -52,22 +54,6 @@
#define R_PU_100K 100000
#define RATIO_MAX_ADC7 BIT(14)
#define DIE_TEMP_ADC7_SCALE_1 -60000
#define DIE_TEMP_ADC7_SCALE_2 20000
#define DIE_TEMP_ADC7_SCALE_FACTOR 1000
#define DIE_TEMP_ADC7_MAX 160000
/**
* 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;
};
/*
* VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
* VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
@ -168,10 +154,18 @@ struct qcom_adc5_scale_type {
};
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_mdec);
int qcom_adc5_prescaling_from_dt(u32 num, u32 den);
int qcom_adc5_hw_settle_time_from_dt(u32 value, const unsigned int *hw_settle);
int qcom_adc5_avg_samples_from_dt(u32 value);
int qcom_adc5_decimation_from_dt(u32 value, const unsigned int *decimation);
int qcom_vadc_decimation_from_dt(u32 value);
#endif /* QCOM_VADC_COMMON_H */

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

@ -13,6 +13,7 @@
struct iio_dev;
struct iio_chan_spec;
struct device;
struct device_node;
/**
* struct iio_channel - everything needed for a consumer to use a channel
@ -97,6 +98,41 @@ void iio_channel_release_all(struct iio_channel *chan);
*/
struct iio_channel *devm_iio_channel_get_all(struct device *dev);
/**
* of_iio_channel_get_by_name() - get description of all that is needed to access channel.
* @np: Pointer to consumer device tree node
* @consumer_channel: Unique name to identify the channel on the consumer
* side. This typically describes the channels use within
* the consumer. E.g. 'battery_voltage'
*/
#ifdef CONFIG_OF
struct iio_channel *of_iio_channel_get_by_name(struct device_node *np, const char *name);
#else
static inline struct iio_channel *
of_iio_channel_get_by_name(struct device_node *np, const char *name)
{
return NULL;
}
#endif
/**
* devm_of_iio_channel_get_by_name() - Resource managed version of of_iio_channel_get_by_name().
* @dev: Pointer to consumer device.
* @np: Pointer to consumer device tree node
* @consumer_channel: Unique name to identify the channel on the consumer
* side. This typically describes the channels use within
* the consumer. E.g. 'battery_voltage'
*
* Returns a pointer to negative errno if it is not able to get the iio channel
* otherwise returns valid pointer for iio channel.
*
* The allocated iio channel is automatically released when the device is
* unbound.
*/
struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
struct device_node *np,
const char *consumer_channel);
struct iio_cb_buffer;
/**
* iio_channel_get_all_cb() - register callback for triggered capture