Commit 4b55dce8 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

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

Jonathan writes:

1st round of IIO new device support, features and cleanups in the 4.20 cycle.

There is a merge commit in here to pull in regmap support for repeatedly
reading the same register (to read out FIFOs).  Used by the adxl372 driver.
This will find uses elsewhere once we tidy up various drivers that are
effectively doing this and relying on not enabling regcache.

New device support
* Analog devices ADXL372 accelerometer
  - new driver for this accelerometer including fifo and and interrupt support.
    Follow up patches enforce trigger validation, add sampling frequency
    control and filter bandwidth control.  A later series added i2c support
    to the existing SPI support.
* ST lsm6dsx
  - rework and add support fo the LSM6DSO 6 axis mems sensor.
* Linear LTC 1660 DAC
  - new driver supporting the LTC 1660 and LTC 1665 SPI DACs.
* Microchip mcp3911 ADC.
  - new driver for this integrated analog front end and ADC.
* Qualcomm SPMI PMIC5 adc driver
  - using the spmi framework, new driver and bindings for this ADC.
    Follow up patch adds some missing channels.

Features
* ad5758
  - support hard reset using a gpio (if provided).
* mpu6050
  - Regulator support
* qcom-spmi-adc5
  - Sanity check the channel numbers provided by DT to make sure the
    driver actually knows about them.
* sc27xx
  - give raw data for channel 20 as it's used on all known boards for
    the headset which needs a custom converstion function.  If it turns
    out someone builds a board where this isn't true we will deal with it
    when it happens.
  - add ADC scale calibration.
* tsl2772
  - support device tree binding to set the proximity led settings.
  - regulator supprot.
  - binding for apds9930 - trivial addition as register compatible with tsl2772.

Cleanups / Minor fixes

* adxl345
  - supress a static checker warning but explicitly checking if the id
    object is null.
* bh1750
  - avoid CONFIG_PM_SLEEP checks.
  - SPDX.
* bme680
  - spelling mistake
  - use clamp rather than open coding.
  - white space and other similar fixes.
  - rename MSK to MASK for clarifty and use GENMASK to specify them.
  - use the FIELD_GET macro rather than a very odd accessor of dividing by
    16 to get the shift.
  - rework to share handing for oversampling of the various channels in a
    unified way.
  - check explicitly for val2 in write_raw function to ensure it is 0.
  - drop some field defines that don't add anything.
* dpot-adc
  - SPDX
* envelope detector
  - SPDX
* isl29501
  - fix an ancient compiler warning mostly because it results in much
    nicer code.
* max30102
  - mark switch fall throughs.
* max44000
  - drop an unused variable.
* max512
  - avoid CONFIG_PM_SLEEP checks.
* max5481
  - use of_device_get_match_data rather than open coding it.
* max5821
  - avoid CONFIG_PM_SLEEP checks.
* max9611
  - explicity cast an enum to an integer to make it totally clear that
    this is intended.
* mcp4018
  - fix an inconsistent MODULE_LICENSE.
  - use of_device_get_match_data rather than open coding it.
* mcp4531
  - use of_device_get_match_data rather than open coding it.
  - SPDX
* mcp4725
  - avoid CONFIG_PM_SLEEP checks.
* mcp4922
  - Fix error handling and prevent writing a negative to when setting the
    output voltage.
* ms5611
  - drop deprecated compatible strings without manufacturer from being
    explicitly listed.  They are handled anyway.
  - SPDX
* multiplexer
  - SPDX
* qcom-vadc
  - fix inconsistent documentation for reg.
* ti-dac5571
  - provide and of_match_table.

* treewide
  - update Michael Hennerich's email address.
  - Use %pOFn rather than device_node.name.
* documentation.
  - tidy up a wrong kernel version for the introduction of the
    position_relative ABI.
parents 064ee3c0 daae7861
......@@ -199,7 +199,7 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_positionrelative_x_raw
What: /sys/bus/iio/devices/iio:deviceX/in_positionrelative_y_raw
KernelVersion: 4.18
KernelVersion: 4.19
Contact: linux-iio@vger.kernel.org
Description:
Relative position in direction x or y on a pad (may be
......
Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer
http://www.analog.com/media/en/technical-documentation/data-sheets/adxl372.pdf
Required properties:
- compatible : should be "adi,adxl372"
- reg: the I2C address or SPI chip select number for the device
Required properties for SPI bus usage:
- spi-max-frequency: Max SPI frequency to use
Optional properties:
- interrupts: interrupt mapping for IRQ as documented in
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Example for a I2C device node:
accelerometer@53 {
compatible = "adi,adxl372";
reg = <0x53>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
};
Example for a SPI device node:
accelerometer@0 {
compatible = "adi,adxl372";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
};
* Microchip MCP3911 Dual channel analog front end (ADC)
Required properties:
- compatible: Should be "microchip,mcp3911"
- reg: SPI chip select number for the device
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt.
Max frequency for this chip is 20MHz.
Optional properties:
- clocks: Phandle and clock identifier for sampling clock
- interrupt-parent: Phandle to the parent interrupt controller
- interrupts: IRQ line for the ADC
- microchip,device-addr: Device address when multiple MCP3911 chips are present on the
same SPI bus. Valid values are 0-3. Defaults to 0.
- vref-supply: Phandle to the external reference voltage supply.
Example:
adc@0 {
compatible = "microchip,mcp3911";
reg = <0>;
interrupt-parent = <&gpio5>;
interrupts = <15 IRQ_TYPE_EDGE_RISING>;
spi-max-frequency = <20000000>;
microchip,device-addr = <0>;
vref-supply = <&vref_reg>;
clocks = <&xtal>;
};
Qualcomm's SPMI PMIC voltage ADC
Qualcomm's SPMI PMIC ADC
SPMI PMIC voltage ADC (VADC) provides interface to clients to read
voltage. The VADC is a 15-bit sigma-delta ADC.
- SPMI PMIC voltage ADC (VADC) provides interface to clients to read
voltage. The VADC is a 15-bit sigma-delta ADC.
- SPMI PMIC5 voltage ADC (ADC) provides interface to clients to read
voltage. The VADC is a 16-bit sigma-delta ADC.
VADC node:
......@@ -9,11 +11,13 @@ VADC node:
Usage: required
Value type: <string>
Definition: Should contain "qcom,spmi-vadc".
Should contain "qcom,spmi-adc5" for PMIC5 ADC driver.
Should contain "qcom,spmi-adc-rev2" for PMIC rev2 ADC driver.
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: VADC base address and length in the SPMI PMIC register map.
Definition: VADC base address in the SPMI PMIC register map.
- #address-cells:
Usage: required
......@@ -45,13 +49,26 @@ Channel node properties:
Definition: ADC channel number.
See include/dt-bindings/iio/qcom,spmi-vadc.h
- label:
Usage: required for "qcom,spmi-adc5" and "qcom,spmi-adc-rev2"
Value type: <empty>
Definition: ADC input of the platform as seen in the schematics.
For thermistor inputs connected to generic AMUX or GPIO inputs
these can vary across platform for the same pins. Hence select
the platform schematics name for this channel.
- qcom,decimation:
Usage: optional
Value type: <u32>
Definition: This parameter is used to decrease ADC sampling rate.
Quicker measurements can be made by reducing decimation ratio.
Valid values are 512, 1024, 2048, 4096.
If property is not found, default value of 512 will be used.
- For compatible property "qcom,spmi-vadc", valid values are
512, 1024, 2048, 4096. If property is not found, default value
of 512 will be used.
- For compatible property "qcom,spmi-adc5", valid values are 250, 420
and 840. If property is not found, default value of 840 is used.
- For compatible property "qcom,spmi-adc-rev2", valid values are 256,
512 and 1024. If property is not present, default value is 1024.
- qcom,pre-scaling:
Usage: optional
......@@ -66,21 +83,38 @@ Channel node properties:
- qcom,ratiometric:
Usage: optional
Value type: <empty>
Definition: Channel calibration type. If this property is specified
VADC will use the VDD reference (1.8V) and GND for channel
calibration. If property is not found, channel will be
calibrated with 0.625V and 1.25V reference channels, also
known as absolute calibration.
Definition: Channel calibration type.
- For compatible property "qcom,spmi-vadc", if this property is
specified VADC will use the VDD reference (1.8V) and GND for
channel calibration. If property is not found, channel will be
calibrated with 0.625V and 1.25V reference channels, also
known as absolute calibration.
- For compatible property "qcom,spmi-adc5" and "qcom,spmi-adc-rev2",
if this property is specified VADC will use the VDD reference
(1.875V) and GND for channel calibration. If property is not found,
channel will be calibrated with 0V and 1.25V reference channels,
also known as absolute calibration.
- qcom,hw-settle-time:
Usage: optional
Value type: <u32>
Definition: Time between AMUX getting configured and the ADC starting
conversion. Delay = 100us * (value) for value < 11, and
2ms * (value - 10) otherwise.
Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800,
900 us and 1, 2, 4, 6, 8, 10 ms
If property is not found, channel will use 0us.
conversion. The 'hw_settle_time' is an index used from valid values
and programmed in hardware to achieve the hardware settling delay.
- For compatible property "qcom,spmi-vadc" and "qcom,spmi-adc-rev2",
Delay = 100us * (hw_settle_time) for hw_settle_time < 11,
and 2ms * (hw_settle_time - 10) otherwise.
Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800,
900 us and 1, 2, 4, 6, 8, 10 ms.
If property is not found, channel will use 0us.
- For compatible property "qcom,spmi-adc5", delay = 15us for
value 0, 100us * (value) for values < 11,
and 2ms * (value - 10) otherwise.
Valid values are: 15, 100, 200, 300, 400, 500, 600, 700, 800,
900 us and 1, 2, 4, 6, 8, 10 ms
Certain controller digital versions have valid values of
15, 100, 200, 300, 400, 500, 600, 700, 1, 2, 4, 8, 16, 32, 64, 128 ms
If property is not found, channel will use 15us.
- qcom,avg-samples:
Usage: optional
......@@ -89,13 +123,18 @@ Channel node properties:
Averaging provides the option to obtain a single measurement
from the ADC that is an average of multiple samples. The value
selected is 2^(value).
Valid values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
If property is not found, 1 sample will be used.
- For compatible property "qcom,spmi-vadc", valid values
are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
If property is not found, 1 sample will be used.
- For compatible property "qcom,spmi-adc5" and "qcom,spmi-adc-rev2",
valid values are: 1, 2, 4, 8, 16
If property is not found, 1 sample will be used.
NOTE:
Following channels, also known as reference point channels, are used for
result calibration and their channel configuration nodes should be defined:
For compatible property "qcom,spmi-vadc" following channels, also known as
reference point channels, are used for result calibration and their channel
configuration nodes should be defined:
VADC_REF_625MV and/or VADC_SPARE1(based on PMIC version) VADC_REF_1250MV,
VADC_GND_REF and VADC_VDD_VADC.
......@@ -104,7 +143,7 @@ Example:
/* VADC node */
pmic_vadc: vadc@3100 {
compatible = "qcom,spmi-vadc";
reg = <0x3100 0x100>;
reg = <0x3100>;
interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -12,6 +12,8 @@ Required properties:
- interrupts: The interrupt number for the ADC device.
- #io-channel-cells: Number of cells in an IIO specifier.
- hwlocks: Reference to a phandle of a hwlock provider node.
- nvmem-cells: A phandle to the calibration cells provided by eFuse device.
- nvmem-cell-names: Should be "big_scale_calib", "small_scale_calib".
Example:
......@@ -32,5 +34,7 @@ Example:
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
#io-channel-cells = <1>;
hwlocks = <&hwlock 4>;
nvmem-cells = <&adc_big_scale>, <&adc_small_scale>;
nvmem-cell-names = "big_scale_calib", "small_scale_calib";
};
};
......@@ -50,6 +50,9 @@ Required properties:
Optional properties:
- reset-gpios : GPIO spec for the RESET pin. If specified, it will be
asserted during driver probe.
- adi,dc-dc-ilim-microamp: The dc-to-dc converter current limit
The following values are currently supported [uA]:
* 150000
......@@ -71,6 +74,8 @@ AD5758 Example:
spi-max-frequency = <1000000>;
spi-cpha;
reset-gpios = <&gpio 22 0>;
adi,dc-dc-mode = <2>;
adi,range-microvolt = <0 10000000>;
adi,dc-dc-ilim-microamp = <200000>;
......
* Linear Technology Micropower octal 8-Bit and 10-Bit DACs
Required properties:
- compatible: Must be one of the following:
"lltc,ltc1660"
"lltc,ltc1665"
- reg: SPI chip select number for the device
- vref-supply: Phandle to the voltage reference supply
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt.
Max frequency for this chip is 5 MHz.
Example:
dac@0 {
compatible = "lltc,ltc1660";
reg = <0>;
spi-max-frequency = <5000000>;
vref-supply = <&vref_reg>;
};
......@@ -20,6 +20,7 @@ Required properties:
bindings.
Optional properties:
- 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
......
......@@ -7,6 +7,7 @@ Required properties:
"st,lsm6dsl"
"st,lsm6dsm"
"st,ism330dlc"
"st,lsm6dso"
- reg: i2c address of the sensor / spi cs line
Optional properties:
......
* AMS/TAOS ALS and proximity sensor
Required properties:
- compatible: Should be one of
"amstaos,tsl2571"
"amstaos,tsl2671"
"amstaos,tmd2671"
"amstaos,tsl2771"
"amstaos,tmd2771"
"amstaos,tsl2572"
"amstaos,tsl2672"
"amstaos,tmd2672"
"amstaos,tsl2772"
"amstaos,tmd2772"
"avago,apds9930"
- reg: the I2C address of the device
Optional properties:
- amstaos,proximity-diodes - proximity diodes to enable. <0>, <1>, or <0 1>
are the only valid values.
- led-max-microamp - current for the proximity LED. Must be 100000, 50000,
25000, or 13000.
- vdd-supply: phandle to the regulator that provides power to the sensor.
- vddio-supply: phandle to the regulator that provides power to the bus.
- interrupts: the sole interrupt generated by the device
Refer to interrupt-controller/interrupts.txt for generic interrupt client
node bindings.
Example:
tsl2772@39 {
compatible = "amstaos,tsl2772";
reg = <0x39>;
interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
vdd-supply = <&pm8941_l17>;
vddio-supply = <&pm8941_lvs1>;
amstaos,proximity-diodes = <0>;
led-max-microamp = <100000>;
};
......@@ -21,16 +21,6 @@ adi,adt7490 +/-1C TDM Extended Temp Range I.C
adi,adxl345 Three-Axis Digital Accelerometer
adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
ams,iaq-core AMS iAQ-Core VOC Sensor
amstaos,tsl2571 AMS/TAOS ALS and proximity sensor
amstaos,tsl2671 AMS/TAOS ALS and proximity sensor
amstaos,tmd2671 AMS/TAOS ALS and proximity sensor
amstaos,tsl2771 AMS/TAOS ALS and proximity sensor
amstaos,tmd2771 AMS/TAOS ALS and proximity sensor
amstaos,tsl2572 AMS/TAOS ALS and proximity sensor
amstaos,tsl2672 AMS/TAOS ALS and proximity sensor
amstaos,tmd2672 AMS/TAOS ALS and proximity sensor
amstaos,tsl2772 AMS/TAOS ALS and proximity sensor
amstaos,tmd2772 AMS/TAOS ALS and proximity sensor
at,24c08 i2c serial eeprom (24cxx)
atmel,at97sc3204t i2c trusted platform module (TPM)
capella,cm32181 CM32181: Ambient Light Sensor
......
......@@ -550,6 +550,15 @@ W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/input/misc/adxl34x.c
ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
M: Stefan Popa <stefan.popa@analog.com>
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/accel/adxl372.c
F: drivers/iio/accel/adxl372_spi.c
F: drivers/iio/accel/adxl372_i2c.c
F: Documentation/devicetree/bindings/iio/accel/adxl372.txt
AF9013 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
......@@ -8614,6 +8623,13 @@ L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/sym53c8xx_2/
LTC1660 DAC DRIVER
M: Marcus Folkesson <marcus.folkesson@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/dac/ltc1660.txt
F: drivers/iio/dac/ltc1660.c
LTC4261 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
......@@ -9550,6 +9566,14 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/microchip/lan743x_*
MICROCHIP / ATMEL MCP3911 ADC DRIVER
M: Marcus Folkesson <marcus.folkesson@gmail.com>
M: Kent Gustavsson <kent@minoris.se>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/adc/mcp3911.c
F: Documentation/devicetree/bindings/iio/adc/mcp3911.txt
MICROCHIP USB251XB DRIVER
M: Richard Leitner <richard.leitner@skidata.com>
L: linux-usb@vger.kernel.org
......
......@@ -60,6 +60,33 @@ config ADXL345_SPI
will be called adxl345_spi and you will also get adxl345_core
for the core module.
config ADXL372
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config ADXL372_SPI
tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver"
depends on SPI
select ADXL372
select REGMAP_SPI
help
Say yes here to add support for the Analog Devices ADXL372 triaxial
acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called adxl372_spi.
config ADXL372_I2C
tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver"
depends on I2C
select ADXL372
select REGMAP_I2C
help
Say yes here to add support for the Analog Devices ADXL372 triaxial
acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called adxl372_i2c.
config BMA180
tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver"
depends on I2C
......
......@@ -9,6 +9,9 @@ obj-$(CONFIG_ADIS16209) += adis16209.o
obj-$(CONFIG_ADXL345) += adxl345_core.o
obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o
obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
obj-$(CONFIG_ADXL372) += adxl372.o
obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
......
......@@ -27,6 +27,9 @@ static int adxl345_i2c_probe(struct i2c_client *client,
{
struct regmap *regmap;
if (!id)
return -ENODEV;
regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
......@@ -35,7 +38,7 @@ static int adxl345_i2c_probe(struct i2c_client *client,
}
return adxl345_core_probe(&client->dev, regmap, id->driver_data,
id ? id->name : NULL);
id->name);
}
static int adxl345_i2c_remove(struct i2c_client *client)
......
// SPDX-License-Identifier: GPL-2.0+
/*
* ADXL372 3-Axis Digital Accelerometer core driver
*
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "adxl372.h"
/* ADXL372 registers definition */
#define ADXL372_DEVID 0x00
#define ADXL372_DEVID_MST 0x01
#define ADXL372_PARTID 0x02
#define ADXL372_STATUS_1 0x04
#define ADXL372_STATUS_2 0x05
#define ADXL372_FIFO_ENTRIES_2 0x06
#define ADXL372_FIFO_ENTRIES_1 0x07
#define ADXL372_X_DATA_H 0x08
#define ADXL372_X_DATA_L 0x09
#define ADXL372_Y_DATA_H 0x0A
#define ADXL372_Y_DATA_L 0x0B
#define ADXL372_Z_DATA_H 0x0C
#define ADXL372_Z_DATA_L 0x0D
#define ADXL372_X_MAXPEAK_H 0x15
#define ADXL372_X_MAXPEAK_L 0x16
#define ADXL372_Y_MAXPEAK_H 0x17
#define ADXL372_Y_MAXPEAK_L 0x18
#define ADXL372_Z_MAXPEAK_H 0x19
#define ADXL372_Z_MAXPEAK_L 0x1A
#define ADXL372_OFFSET_X 0x20
#define ADXL372_OFFSET_Y 0x21
#define ADXL372_OFFSET_Z 0x22
#define ADXL372_X_THRESH_ACT_H 0x23
#define ADXL372_X_THRESH_ACT_L 0x24
#define ADXL372_Y_THRESH_ACT_H 0x25
#define ADXL372_Y_THRESH_ACT_L 0x26
#define ADXL372_Z_THRESH_ACT_H 0x27
#define ADXL372_Z_THRESH_ACT_L 0x28
#define ADXL372_TIME_ACT 0x29
#define ADXL372_X_THRESH_INACT_H 0x2A
#define ADXL372_X_THRESH_INACT_L 0x2B
#define ADXL372_Y_THRESH_INACT_H 0x2C
#define ADXL372_Y_THRESH_INACT_L 0x2D
#define ADXL372_Z_THRESH_INACT_H 0x2E
#define ADXL372_Z_THRESH_INACT_L 0x2F
#define ADXL372_TIME_INACT_H 0x30
#define ADXL372_TIME_INACT_L 0x31
#define ADXL372_X_THRESH_ACT2_H 0x32
#define ADXL372_X_THRESH_ACT2_L 0x33
#define ADXL372_Y_THRESH_ACT2_H 0x34
#define ADXL372_Y_THRESH_ACT2_L 0x35
#define ADXL372_Z_THRESH_ACT2_H 0x36
#define ADXL372_Z_THRESH_ACT2_L 0x37
#define ADXL372_HPF 0x38
#define ADXL372_FIFO_SAMPLES 0x39
#define ADXL372_FIFO_CTL 0x3A
#define ADXL372_INT1_MAP 0x3B
#define ADXL372_INT2_MAP 0x3C
#define ADXL372_TIMING 0x3D
#define ADXL372_MEASURE 0x3E
#define ADXL372_POWER_CTL 0x3F
#define ADXL372_SELF_TEST 0x40
#define ADXL372_RESET 0x41
#define ADXL372_FIFO_DATA 0x42
#define ADXL372_DEVID_VAL 0xAD
#define ADXL372_PARTID_VAL 0xFA
#define ADXL372_RESET_CODE 0x52
/* ADXL372_POWER_CTL */
#define ADXL372_POWER_CTL_MODE_MSK GENMASK_ULL(1, 0)
#define ADXL372_POWER_CTL_MODE(x) (((x) & 0x3) << 0)
/* ADXL372_MEASURE */
#define ADXL372_MEASURE_LINKLOOP_MSK GENMASK_ULL(5, 4)
#define ADXL372_MEASURE_LINKLOOP_MODE(x) (((x) & 0x3) << 4)
#define ADXL372_MEASURE_BANDWIDTH_MSK GENMASK_ULL(2, 0)
#define ADXL372_MEASURE_BANDWIDTH_MODE(x) (((x) & 0x7) << 0)
/* ADXL372_TIMING */
#define ADXL372_TIMING_ODR_MSK GENMASK_ULL(7, 5)
#define ADXL372_TIMING_ODR_MODE(x) (((x) & 0x7) << 5)
/* ADXL372_FIFO_CTL */
#define ADXL372_FIFO_CTL_FORMAT_MSK GENMASK(5, 3)
#define ADXL372_FIFO_CTL_FORMAT_MODE(x) (((x) & 0x7) << 3)
#define ADXL372_FIFO_CTL_MODE_MSK GENMASK(2, 1)
#define ADXL372_FIFO_CTL_MODE_MODE(x) (((x) & 0x3) << 1)
#define ADXL372_FIFO_CTL_SAMPLES_MSK BIT(1)
#define ADXL372_FIFO_CTL_SAMPLES_MODE(x) (((x) > 0xFF) ? 1 : 0)
/* ADXL372_STATUS_1 */
#define ADXL372_STATUS_1_DATA_RDY(x) (((x) >> 0) & 0x1)
#define ADXL372_STATUS_1_FIFO_RDY(x) (((x) >> 1) & 0x1)
#define ADXL372_STATUS_1_FIFO_FULL(x) (((x) >> 2) & 0x1)
#define ADXL372_STATUS_1_FIFO_OVR(x) (((x) >> 3) & 0x1)
#define ADXL372_STATUS_1_USR_NVM_BUSY(x) (((x) >> 5) & 0x1)
#define ADXL372_STATUS_1_AWAKE(x) (((x) >> 6) & 0x1)
#define ADXL372_STATUS_1_ERR_USR_REGS(x) (((x) >> 7) & 0x1)
/* ADXL372_INT1_MAP */
#define ADXL372_INT1_MAP_DATA_RDY_MSK BIT(0)
#define ADXL372_INT1_MAP_DATA_RDY_MODE(x) (((x) & 0x1) << 0)
#define ADXL372_INT1_MAP_FIFO_RDY_MSK BIT(1)
#define ADXL372_INT1_MAP_FIFO_RDY_MODE(x) (((x) & 0x1) << 1)
#define ADXL372_INT1_MAP_FIFO_FULL_MSK BIT(2)
#define ADXL372_INT1_MAP_FIFO_FULL_MODE(x) (((x) & 0x1) << 2)
#define ADXL372_INT1_MAP_FIFO_OVR_MSK BIT(3)
#define ADXL372_INT1_MAP_FIFO_OVR_MODE(x) (((x) & 0x1) << 3)
#define ADXL372_INT1_MAP_INACT_MSK BIT(4)
#define ADXL372_INT1_MAP_INACT_MODE(x) (((x) & 0x1) << 4)
#define ADXL372_INT1_MAP_ACT_MSK BIT(5)
#define ADXL372_INT1_MAP_ACT_MODE(x) (((x) & 0x1) << 5)
#define ADXL372_INT1_MAP_AWAKE_MSK BIT(6)
#define ADXL372_INT1_MAP_AWAKE_MODE(x) (((x) & 0x1) << 6)
#define ADXL372_INT1_MAP_LOW_MSK BIT(7)
#define ADXL372_INT1_MAP_LOW_MODE(x) (((x) & 0x1) << 7)
/* The ADXL372 includes a deep, 512 sample FIFO buffer */
#define ADXL372_FIFO_SIZE 512
/*
* At +/- 200g with 12-bit resolution, scale is computed as:
* (200 + 200) * 9.81 / (2^12 - 1) = 0.958241
*/
#define ADXL372_USCALE 958241
enum adxl372_op_mode {
ADXL372_STANDBY,
ADXL372_WAKE_UP,
ADXL372_INSTANT_ON,
ADXL372_FULL_BW_MEASUREMENT,
};
enum adxl372_act_proc_mode {
ADXL372_DEFAULT,
ADXL372_LINKED,
ADXL372_LOOPED,
};
enum adxl372_th_activity {
ADXL372_ACTIVITY,
ADXL372_ACTIVITY2,
ADXL372_INACTIVITY,
};
enum adxl372_odr {
ADXL372_ODR_400HZ,
ADXL372_ODR_800HZ,
ADXL372_ODR_1600HZ,
ADXL372_ODR_3200HZ,
ADXL372_ODR_6400HZ,
};
enum adxl372_bandwidth {
ADXL372_BW_200HZ,
ADXL372_BW_400HZ,
ADXL372_BW_800HZ,
ADXL372_BW_1600HZ,
ADXL372_BW_3200HZ,
};
static const unsigned int adxl372_th_reg_high_addr[3] = {
[ADXL372_ACTIVITY] = ADXL372_X_THRESH_ACT_H,
[ADXL372_ACTIVITY2] = ADXL372_X_THRESH_ACT2_H,
[ADXL372_INACTIVITY] = ADXL372_X_THRESH_INACT_H,
};
enum adxl372_fifo_format {
ADXL372_XYZ_FIFO,
ADXL372_X_FIFO,
ADXL372_Y_FIFO,
ADXL372_XY_FIFO,
ADXL372_Z_FIFO,
ADXL372_XZ_FIFO,
ADXL372_YZ_FIFO,
ADXL372_XYZ_PEAK_FIFO,
};
enum adxl372_fifo_mode {
ADXL372_FIFO_BYPASSED,
ADXL372_FIFO_STREAMED,
ADXL372_FIFO_TRIGGERED,
ADXL372_FIFO_OLD_SAVED
};
static const int adxl372_samp_freq_tbl[5] = {
400, 800, 1600, 3200, 6400,
};
static const int adxl372_bw_freq_tbl[5] = {
200, 400, 800, 1600, 3200,
};
struct adxl372_axis_lookup {
unsigned int bits;
enum adxl372_fifo_format fifo_format;
};
static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
{ BIT(0), ADXL372_X_FIFO },
{ BIT(1), ADXL372_Y_FIFO },
{ BIT(2), ADXL372_Z_FIFO },
{ BIT(0) | BIT(1), ADXL372_XY_FIFO },
{ BIT(0) | BIT(2), ADXL372_XZ_FIFO },
{ BIT(1) | BIT(2), ADXL372_YZ_FIFO },
{ BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO },
};
#define ADXL372_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
.realbits = 12, \
.storagebits = 16, \
.shift = 4, \
}, \
}
static const struct iio_chan_spec adxl372_channels[] = {
ADXL372_ACCEL_CHANNEL(0, ADXL372_X_DATA_H, X),
ADXL372_ACCEL_CHANNEL(1, ADXL372_Y_DATA_H, Y),
ADXL372_ACCEL_CHANNEL(2, ADXL372_Z_DATA_H, Z),
};
struct adxl372_state {
int irq;
struct device *dev;
struct regmap *regmap;
struct iio_trigger *dready_trig;
enum adxl372_fifo_mode fifo_mode;
enum adxl372_fifo_format fifo_format;
enum adxl372_op_mode op_mode;
enum adxl372_act_proc_mode act_proc_mode;
enum adxl372_odr odr;
enum adxl372_bandwidth bw;
u32 act_time_ms;
u32 inact_time_ms;
u8 fifo_set_size;
u8 int1_bitmask;
u8 int2_bitmask;
u16 watermark;
__be16 fifo_buf[ADXL372_FIFO_SIZE];
};
static const unsigned long adxl372_channel_masks[] = {
BIT(0), BIT(1), BIT(2),
BIT(0) | BIT(1),
BIT(0) | BIT(2),
BIT(1) | BIT(2),
BIT(0) | BIT(1) | BIT(2),
0
};
static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
{
__be16 regval;
int ret;
ret = regmap_bulk_read(st->regmap, addr, &regval, sizeof(regval));
if (ret < 0)
return ret;
return be16_to_cpu(regval);
}
static int adxl372_set_op_mode(struct adxl372_state *st,
enum adxl372_op_mode op_mode)
{
int ret;
ret = regmap_update_bits(st->regmap, ADXL372_POWER_CTL,
ADXL372_POWER_CTL_MODE_MSK,
ADXL372_POWER_CTL_MODE(op_mode));
if (ret < 0)
return ret;
st->op_mode = op_mode;
return ret;
}
static int adxl372_set_odr(struct adxl372_state *st,
enum adxl372_odr odr)
{
int ret;
ret = regmap_update_bits(st->regmap, ADXL372_TIMING,
ADXL372_TIMING_ODR_MSK,
ADXL372_TIMING_ODR_MODE(odr));
if (ret < 0)
return ret;
st->odr = odr;
return ret;
}
static int adxl372_find_closest_match(const int *array,
unsigned int size, int val)
{
int i;
for (i = 0; i < size; i++) {
if (val <= array[i])
return i;
}
return size - 1;
}
static int adxl372_set_bandwidth(struct adxl372_state *st,
enum adxl372_bandwidth bw)
{
int ret;
ret = regmap_update_bits(st->regmap, ADXL372_MEASURE,
ADXL372_MEASURE_BANDWIDTH_MSK,
ADXL372_MEASURE_BANDWIDTH_MODE(bw));
if (ret < 0)
return ret;
st->bw = bw;
return ret;
}
static int adxl372_set_act_proc_mode(struct adxl372_state *st,
enum adxl372_act_proc_mode mode)
{
int ret;
ret = regmap_update_bits(st->regmap,
ADXL372_MEASURE,
ADXL372_MEASURE_LINKLOOP_MSK,
ADXL372_MEASURE_LINKLOOP_MODE(mode));
if (ret < 0)
return ret;
st->act_proc_mode = mode;
return ret;
}
static int adxl372_set_activity_threshold(struct adxl372_state *st,
enum adxl372_th_activity act,
bool ref_en, bool enable,
unsigned int threshold)
{
unsigned char buf[6];
unsigned char th_reg_high_val, th_reg_low_val, th_reg_high_addr;
/* scale factor is 100 mg/code */
th_reg_high_val = (threshold / 100) >> 3;
th_reg_low_val = ((threshold / 100) << 5) | (ref_en << 1) | enable;
th_reg_high_addr = adxl372_th_reg_high_addr[act];
buf[0] = th_reg_high_val;
buf[1] = th_reg_low_val;
buf[2] = th_reg_high_val;
buf[3] = th_reg_low_val;
buf[4] = th_reg_high_val;
buf[5] = th_reg_low_val;
return regmap_bulk_write(st->regmap, th_reg_high_addr,
buf, ARRAY_SIZE(buf));
}
static int adxl372_set_activity_time_ms(struct adxl372_state *st,
unsigned int act_time_ms)
{
unsigned int reg_val, scale_factor;
int ret;
/*
* 3.3 ms per code is the scale factor of the TIME_ACT register for
* ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below.
*/
if (st->odr == ADXL372_ODR_6400HZ)
scale_factor = 3300;
else
scale_factor = 6600;
reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor);
/* TIME_ACT register is 8 bits wide */
if (reg_val > 0xFF)
reg_val = 0xFF;
ret = regmap_write(st->regmap, ADXL372_TIME_ACT, reg_val);
if (ret < 0)
return ret;
st->act_time_ms = act_time_ms;
return ret;
}
static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
unsigned int inact_time_ms)
{
unsigned int reg_val_h, reg_val_l, res, scale_factor;
int ret;
/*
* 13 ms per code is the scale factor of the TIME_INACT register for
* ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below.
*/
if (st->odr == ADXL372_ODR_6400HZ)
scale_factor = 13;
else
scale_factor = 26;
res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor);
reg_val_h = (res >> 8) & 0xFF;
reg_val_l = res & 0xFF;
ret = regmap_write(st->regmap, ADXL372_TIME_INACT_H, reg_val_h);
if (ret < 0)
return ret;
ret = regmap_write(st->regmap, ADXL372_TIME_INACT_L, reg_val_l);
if (ret < 0)
return ret;
st->inact_time_ms = inact_time_ms;
return ret;
}
static int adxl372_set_interrupts(struct adxl372_state *st,
unsigned char int1_bitmask,
unsigned char int2_bitmask)
{
int ret;
ret = regmap_write(st->regmap, ADXL372_INT1_MAP, int1_bitmask);
if (ret < 0)
return ret;
return regmap_write(st->regmap, ADXL372_INT2_MAP, int2_bitmask);
}
static int adxl372_configure_fifo(struct adxl372_state *st)
{
unsigned int fifo_samples, fifo_ctl;
int ret;
/* FIFO must be configured while in standby mode */
ret = adxl372_set_op_mode(st, ADXL372_STANDBY);
if (ret < 0)
return ret;
fifo_samples = st->watermark & 0xFF;
fifo_ctl = ADXL372_FIFO_CTL_FORMAT_MODE(st->fifo_format) |
ADXL372_FIFO_CTL_MODE_MODE(st->fifo_mode) |
ADXL372_FIFO_CTL_SAMPLES_MODE(st->watermark);
ret = regmap_write(st->regmap, ADXL372_FIFO_SAMPLES, fifo_samples);
if (ret < 0)
return ret;
ret = regmap_write(st->regmap, ADXL372_FIFO_CTL, fifo_ctl);
if (ret < 0)
return ret;
return adxl372_set_op_mode(st, ADXL372_FULL_BW_MEASUREMENT);
}
static int adxl372_get_status(struct adxl372_state *st,
u8 *status1, u8 *status2,
u16 *fifo_entries)
{
__be32 buf;
u32 val;
int ret;
/* STATUS1, STATUS2, FIFO_ENTRIES2 and FIFO_ENTRIES are adjacent regs */
ret = regmap_bulk_read(st->regmap, ADXL372_STATUS_1,
&buf, sizeof(buf));
if (ret < 0)
return ret;
val = be32_to_cpu(buf);
*status1 = (val >> 24) & 0x0F;
*status2 = (val >> 16) & 0x0F;
/*
* FIFO_ENTRIES contains the least significant byte, and FIFO_ENTRIES2
* contains the two most significant bits
*/
*fifo_entries = val & 0x3FF;
return ret;
}
static irqreturn_t adxl372_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adxl372_state *st = iio_priv(indio_dev);
u8 status1, status2;
u16 fifo_entries;
int i, ret;
ret = adxl372_get_status(st, &status1, &status2, &fifo_entries);
if (ret < 0)
goto err;
if (st->fifo_mode != ADXL372_FIFO_BYPASSED &&
ADXL372_STATUS_1_FIFO_FULL(status1)) {
/*
* When reading data from multiple axes from the FIFO,
* to ensure that data is not overwritten and stored out
* of order at least one sample set must be left in the
* FIFO after every read.
*/
fifo_entries -= st->fifo_set_size;
/* Read data from the FIFO */
ret = regmap_noinc_read(st->regmap, ADXL372_FIFO_DATA,
st->fifo_buf,
fifo_entries * sizeof(u16));
if (ret < 0)
goto err;
/* Each sample is 2 bytes */
for (i = 0; i < fifo_entries * sizeof(u16);
i += st->fifo_set_size * sizeof(u16))
iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
}
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int adxl372_setup(struct adxl372_state *st)
{
unsigned int regval;
int ret;
ret = regmap_read(st->regmap, ADXL372_DEVID, &regval);
if (ret < 0)
return ret;
if (regval != ADXL372_DEVID_VAL) {
dev_err(st->dev, "Invalid chip id %x\n", regval);
return -ENODEV;
}
ret = adxl372_set_op_mode(st, ADXL372_STANDBY);
if (ret < 0)
return ret;
/* Set threshold for activity detection to 1g */
ret = adxl372_set_activity_threshold(st, ADXL372_ACTIVITY,
true, true, 1000);
if (ret < 0)
return ret;
/* Set threshold for inactivity detection to 100mg */
ret = adxl372_set_activity_threshold(st, ADXL372_INACTIVITY,
true, true, 100);
if (ret < 0)
return ret;
/* Set activity processing in Looped mode */
ret = adxl372_set_act_proc_mode(st, ADXL372_LOOPED);
if (ret < 0)
return ret;
ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ);
if (ret < 0)
return ret;
ret = adxl372_set_bandwidth(st, ADXL372_BW_3200HZ);
if (ret < 0)
return ret;
/* Set activity timer to 1ms */
ret = adxl372_set_activity_time_ms(st, 1);
if (ret < 0)
return ret;
/* Set inactivity timer to 10s */
ret = adxl372_set_inactivity_time_ms(st, 10000);
if (ret < 0)
return ret;
/* Set the mode of operation to full bandwidth measurement mode */
return adxl372_set_op_mode(st, ADXL372_FULL_BW_MEASUREMENT);
}
static int adxl372_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
unsigned int *readval)
{
struct adxl372_state *st = iio_priv(indio_dev);
if (readval)
return regmap_read(st->regmap, reg, readval);
else
return regmap_write(st->regmap, reg, writeval);
}
static int adxl372_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
struct adxl372_state *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = adxl372_read_axis(st, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = sign_extend32(ret >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = ADXL372_USCALE;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = adxl372_samp_freq_tbl[st->odr];
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = adxl372_bw_freq_tbl[st->bw];
return IIO_VAL_INT;
}
return -EINVAL;
}
static int adxl372_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
{
struct adxl372_state *st = iio_priv(indio_dev);
int odr_index, bw_index, ret;
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl,
ARRAY_SIZE(adxl372_samp_freq_tbl),
val);
ret = adxl372_set_odr(st, odr_index);
if (ret < 0)
return ret;
/*
* The timer period depends on the ODR selected.
* At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms
*/
ret = adxl372_set_activity_time_ms(st, st->act_time_ms);
if (ret < 0)
return ret;
/*
* The timer period depends on the ODR selected.
* At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms
*/
ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms);
if (ret < 0)
return ret;
/*
* The maximum bandwidth is constrained to at most half of
* the ODR to ensure that the Nyquist criteria is not violated
*/
if (st->bw > odr_index)
ret = adxl372_set_bandwidth(st, odr_index);
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl,
ARRAY_SIZE(adxl372_bw_freq_tbl),
val);
return adxl372_set_bandwidth(st, bw_index);
default:
return -EINVAL;
}
}
static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adxl372_state *st = iio_priv(indio_dev);
int i;
size_t len = 0;
for (i = 0; i <= st->odr; i++)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%d ", adxl372_bw_freq_tbl[i]);
buf[len - 1] = '\n';
return len;
}
static ssize_t adxl372_get_fifo_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adxl372_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->fifo_mode);
}
static ssize_t adxl372_get_fifo_watermark(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adxl372_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->watermark);
}
static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
static IIO_CONST_ATTR(hwfifo_watermark_max,
__stringify(ADXL372_FIFO_SIZE));
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
adxl372_get_fifo_watermark, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
adxl372_get_fifo_enabled, NULL, 0);
static const struct attribute *adxl372_fifo_attributes[] = {
&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
&iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
NULL,
};
static int adxl372_set_watermark(struct iio_dev *indio_dev, unsigned int val)
{
struct adxl372_state *st = iio_priv(indio_dev);
if (val > ADXL372_FIFO_SIZE)
val = ADXL372_FIFO_SIZE;
st->watermark = val;
return 0;
}
static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
{
struct adxl372_state *st = iio_priv(indio_dev);
unsigned int mask;
int i, ret;
ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
if (ret < 0)
return ret;
mask = *indio_dev->active_scan_mask;
for (i = 0; i < ARRAY_SIZE(adxl372_axis_lookup_table); i++) {
if (mask == adxl372_axis_lookup_table[i].bits)
break;
}
if (i == ARRAY_SIZE(adxl372_axis_lookup_table))
return -EINVAL;
st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
/*
* The 512 FIFO samples can be allotted in several ways, such as:
* 170 sample sets of concurrent 3-axis data
* 256 sample sets of concurrent 2-axis data (user selectable)
* 512 sample sets of single-axis data
*/
if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE)
st->watermark = (ADXL372_FIFO_SIZE / st->fifo_set_size);
st->fifo_mode = ADXL372_FIFO_STREAMED;
ret = adxl372_configure_fifo(st);
if (ret < 0) {
st->fifo_mode = ADXL372_FIFO_BYPASSED;
adxl372_set_interrupts(st, 0, 0);
return ret;
}
return iio_triggered_buffer_postenable(indio_dev);
}
static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
{
struct adxl372_state *st = iio_priv(indio_dev);
int ret;
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret < 0)
return ret;
adxl372_set_interrupts(st, 0, 0);
st->fifo_mode = ADXL372_FIFO_BYPASSED;
adxl372_configure_fifo(st);
return 0;
}
static const struct iio_buffer_setup_ops adxl372_buffer_ops = {
.postenable = adxl372_buffer_postenable,
.predisable = adxl372_buffer_predisable,
};
static int adxl372_dready_trig_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct adxl372_state *st = iio_priv(indio_dev);
unsigned long int mask = 0;
if (state)
mask = ADXL372_INT1_MAP_FIFO_FULL_MSK;
return adxl372_set_interrupts(st, mask, 0);
}
static int adxl372_validate_trigger(struct iio_dev *indio_dev,
struct iio_trigger *trig)
{
struct adxl372_state *st = iio_priv(indio_dev);
if (st->dready_trig != trig)
return -EINVAL;
return 0;
}
static const struct iio_trigger_ops adxl372_trigger_ops = {
.validate_device = &iio_trigger_validate_own_device,
.set_trigger_state = adxl372_dready_trig_set_state,
};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
0444, adxl372_show_filter_freq_avail, NULL, 0);
static struct attribute *adxl372_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group adxl372_attrs_group = {
.attrs = adxl372_attributes,
};
static const struct iio_info adxl372_info = {
.validate_trigger = &adxl372_validate_trigger,
.attrs = &adxl372_attrs_group,
.read_raw = adxl372_read_raw,
.write_raw = adxl372_write_raw,
.debugfs_reg_access = &adxl372_reg_access,
.hwfifo_set_watermark = adxl372_set_watermark,
};
bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
{
return (reg == ADXL372_FIFO_DATA);
}
EXPORT_SYMBOL_GPL(adxl372_readable_noinc_reg);
int adxl372_probe(struct device *dev, struct regmap *regmap,
int irq, const char *name)
{
struct iio_dev *indio_dev;
struct adxl372_state *st;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
st->dev = dev;
st->regmap = regmap;
st->irq = irq;
indio_dev->channels = adxl372_channels;
indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
indio_dev->available_scan_masks = adxl372_channel_masks;
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &adxl372_info;
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
ret = adxl372_setup(st);
if (ret < 0) {
dev_err(dev, "ADXL372 setup failed\n");
return ret;
}
ret = devm_iio_triggered_buffer_setup(dev,
indio_dev, NULL,
adxl372_trigger_handler,
&adxl372_buffer_ops);
if (ret < 0)
return ret;
iio_buffer_set_attrs(indio_dev->buffer, adxl372_fifo_attributes);
if (st->irq) {
st->dready_trig = devm_iio_trigger_alloc(dev,
"%s-dev%d",
indio_dev->name,
indio_dev->id);
if (st->dready_trig == NULL)
return -ENOMEM;
st->dready_trig->ops = &adxl372_trigger_ops;
st->dready_trig->dev.parent = dev;
iio_trigger_set_drvdata(st->dready_trig, indio_dev);
ret = devm_iio_trigger_register(dev, st->dready_trig);
if (ret < 0)
return ret;
indio_dev->trig = iio_trigger_get(st->dready_trig);
ret = devm_request_threaded_irq(dev, st->irq,
iio_trigger_generic_data_rdy_poll,
NULL,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
indio_dev->name, st->dready_trig);
if (ret < 0)
return ret;
}
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(adxl372_probe);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* ADXL372 3-Axis Digital Accelerometer
*
* Copyright 2018 Analog Devices Inc.
*/
#ifndef _ADXL372_H_
#define _ADXL372_H_
#define ADXL372_REVID 0x03
int adxl372_probe(struct device *dev, struct regmap *regmap,
int irq, const char *name);
bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg);
#endif /* _ADXL372_H_ */
// SPDX-License-Identifier: GPL-2.0+
/*
* ADXL372 3-Axis Digital Accelerometer I2C driver
*
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "adxl372.h"
static const struct regmap_config adxl372_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.readable_noinc_reg = adxl372_readable_noinc_reg,
};
static int adxl372_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
unsigned int regval;
int ret;
regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
ret = regmap_read(regmap, ADXL372_REVID, &regval);
if (ret < 0)
return ret;
/* Starting with the 3rd revision an I2C chip bug was fixed */
if (regval < 3)
dev_warn(&client->dev,
"I2C might not work properly with other devices on the bus");
return adxl372_probe(&client->dev, regmap, client->irq, id->name);
}
static const struct i2c_device_id adxl372_i2c_id[] = {
{ "adxl372", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
static struct i2c_driver adxl372_i2c_driver = {
.driver = {
.name = "adxl372_i2c",
},
.probe = adxl372_i2c_probe,
.id_table = adxl372_i2c_id,
};
module_i2c_driver(adxl372_i2c_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0+
/*
* ADXL372 3-Axis Digital Accelerometer SPI driver
*
* Copyright 2018 Analog Devices Inc.
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "adxl372.h"
static const struct regmap_config adxl372_spi_regmap_config = {
.reg_bits = 7,
.pad_bits = 1,
.val_bits = 8,
.read_flag_mask = BIT(0),
.readable_noinc_reg = adxl372_readable_noinc_reg,
};
static int adxl372_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return adxl372_probe(&spi->dev, regmap, spi->irq, id->name);
}
static const struct spi_device_id adxl372_spi_id[] = {
{ "adxl372", 0 },
{}
};
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
static struct spi_driver adxl372_spi_driver = {
.driver = {
.name = "adxl372_spi",
},
.probe = adxl372_spi_probe,
.id_table = adxl372_spi_id,
};
module_spi_driver(adxl372_spi_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
MODULE_LICENSE("GPL");
......@@ -501,6 +501,16 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
config MCP3911
tristate "Microchip Technology MCP3911 driver"
depends on SPI
help
Say yes here to build support for Microchip Technology's MCP3911
analog to digital converter.
This driver can also be built as a module. If so, the module will be
called mcp3911.
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
......@@ -596,6 +606,26 @@ config QCOM_SPMI_VADC
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-vadc.
config QCOM_SPMI_ADC5
tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC"
depends on SPMI
select REGMAP_SPMI
select QCOM_VADC_COMMON
help
This is the IIO Voltage PMIC5 ADC driver for Qualcomm Technologies Inc.
The driver supports multiple channels read. The ADC is a 16-bit
sigma-delta ADC. The hardware supports calibrated results for
conversion requests and clients include reading voltage phone
power, on board system thermistors connected to the PMIC ADC,
PMIC die temperature, charger temperature, battery current, USB voltage
input, voltage signals connected to supported PMIC GPIO inputs. The
hardware supports internal pull-up for thermistors and can choose between
a 100k, 30k and 400k pull up using the ADC channels.
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-adc5.
config RCAR_GYRO_ADC
tristate "Renesas R-Car GyroADC driver"
depends on ARCH_RCAR_GEN2 || COMPILE_TEST
......
......@@ -47,12 +47,14 @@ obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
......
......@@ -385,6 +385,6 @@ static struct spi_driver ad7298_driver = {
};
module_spi_driver(ad7298_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
MODULE_LICENSE("GPL v2");
......@@ -328,6 +328,6 @@ static struct spi_driver ad7476_driver = {
};
module_spi_driver(ad7476_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
MODULE_LICENSE("GPL v2");
......@@ -822,6 +822,6 @@ static struct spi_driver ad7793_driver = {
};
module_spi_driver(ad7793_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs");
MODULE_LICENSE("GPL v2");
......@@ -362,6 +362,6 @@ static struct spi_driver ad7887_driver = {
};
module_spi_driver(ad7887_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
MODULE_LICENSE("GPL v2");
......@@ -363,7 +363,7 @@ static struct spi_driver ad7923_driver = {
};
module_spi_driver(ad7923_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_LICENSE("GPL v2");
......@@ -892,6 +892,6 @@ static struct i2c_driver ad799x_driver = {
};
module_i2c_driver(ad799x_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD799x ADC");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for an envelope detector using a DAC and a comparator
*
* Copyright (C) 2016 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
......
......@@ -289,7 +289,7 @@ static int max9611_read_csa_voltage(struct max9611_dev *max9611,
return ret;
if (*adc_raw > 0) {
*csa_gain = gain_selectors[i];
*csa_gain = (enum max9611_csa_gain)gain_selectors[i];
return 0;
}
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Microchip MCP3911, Two-channel Analog Front End
*
* Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
* Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#define MCP3911_REG_CHANNEL0 0x00
#define MCP3911_REG_CHANNEL1 0x03
#define MCP3911_REG_MOD 0x06
#define MCP3911_REG_PHASE 0x07
#define MCP3911_REG_GAIN 0x09
#define MCP3911_REG_STATUSCOM 0x0a
#define MCP3911_STATUSCOM_CH1_24WIDTH BIT(4)
#define MCP3911_STATUSCOM_CH0_24WIDTH BIT(3)
#define MCP3911_STATUSCOM_EN_OFFCAL BIT(2)
#define MCP3911_STATUSCOM_EN_GAINCAL BIT(1)
#define MCP3911_REG_CONFIG 0x0c
#define MCP3911_CONFIG_CLKEXT BIT(1)
#define MCP3911_CONFIG_VREFEXT BIT(2)
#define MCP3911_REG_OFFCAL_CH0 0x0e
#define MCP3911_REG_GAINCAL_CH0 0x11
#define MCP3911_REG_OFFCAL_CH1 0x14
#define MCP3911_REG_GAINCAL_CH1 0x17
#define MCP3911_REG_VREFCAL 0x1a
#define MCP3911_CHANNEL(x) (MCP3911_REG_CHANNEL0 + x * 3)
#define MCP3911_OFFCAL(x) (MCP3911_REG_OFFCAL_CH0 + x * 6)
/* Internal voltage reference in uV */
#define MCP3911_INT_VREF_UV 1200000
#define MCP3911_REG_READ(reg, id) ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff)
#define MCP3911_REG_WRITE(reg, id) ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff)
#define MCP3911_NUM_CHANNELS 2
struct mcp3911 {
struct spi_device *spi;
struct mutex lock;
struct regulator *vref;
struct clk *clki;
u32 dev_addr;
};
static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
{
int ret;
reg = MCP3911_REG_READ(reg, adc->dev_addr);
ret = spi_write_then_read(adc->spi, &reg, 1, val, len);
if (ret < 0)
return ret;
be32_to_cpus(val);
*val >>= ((4 - len) * 8);
dev_dbg(&adc->spi->dev, "reading 0x%x from register 0x%x\n", *val,
reg >> 1);
return ret;
}
static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
{
dev_dbg(&adc->spi->dev, "writing 0x%x to register 0x%x\n", val, reg);
val <<= (3 - len) * 8;
cpu_to_be32s(&val);
val |= MCP3911_REG_WRITE(reg, adc->dev_addr);
return spi_write(adc->spi, &val, len + 1);
}
static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
u32 val, u8 len)
{
u32 tmp;
int ret;
ret = mcp3911_read(adc, reg, &tmp, len);
if (ret)
return ret;
val &= mask;
val |= tmp & ~mask;
return mcp3911_write(adc, reg, val, len);
}
static int mcp3911_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct mcp3911 *adc = iio_priv(indio_dev);
int ret = -EINVAL;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = mcp3911_read(adc,
MCP3911_CHANNEL(channel->channel), val, 3);
if (ret)
goto out;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_OFFSET:
ret = mcp3911_read(adc,
MCP3911_OFFCAL(channel->channel), val, 3);
if (ret)
goto out;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
if (adc->vref) {
ret = regulator_get_voltage(adc->vref);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"failed to get vref voltage: %d\n",
ret);
goto out;
}
*val = ret / 1000;
} else {
*val = MCP3911_INT_VREF_UV;
}
*val2 = 24;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
}
out:
mutex_unlock(&adc->lock);
return ret;
}
static int mcp3911_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int val,
int val2, long mask)
{
struct mcp3911 *adc = iio_priv(indio_dev);
int ret = -EINVAL;
mutex_lock(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_OFFSET:
if (val2 != 0) {
ret = -EINVAL;
goto out;
}
/* Write offset */
ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val,
3);
if (ret)
goto out;
/* Enable offset*/
ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM,
MCP3911_STATUSCOM_EN_OFFCAL,
MCP3911_STATUSCOM_EN_OFFCAL, 2);
break;
}
out:
mutex_unlock(&adc->lock);
return ret;
}
#define MCP3911_CHAN(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = idx, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET) | \
BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mcp3911_channels[] = {
MCP3911_CHAN(0),
MCP3911_CHAN(1),
};
static const struct iio_info mcp3911_info = {
.read_raw = mcp3911_read_raw,
.write_raw = mcp3911_write_raw,
};
static int mcp3911_config(struct mcp3911 *adc, struct device_node *of_node)
{
u32 configreg;
int ret;
of_property_read_u32(of_node, "device-addr", &adc->dev_addr);
if (adc->dev_addr > 3) {
dev_err(&adc->spi->dev,
"invalid device address (%i). Must be in range 0-3.\n",
adc->dev_addr);
return -EINVAL;
}
dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &configreg, 2);
if (ret)
return ret;
if (adc->vref) {
dev_dbg(&adc->spi->dev, "use external voltage reference\n");
configreg |= MCP3911_CONFIG_VREFEXT;
} else {
dev_dbg(&adc->spi->dev,
"use internal voltage reference (1.2V)\n");
configreg &= ~MCP3911_CONFIG_VREFEXT;
}
if (adc->clki) {
dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
configreg |= MCP3911_CONFIG_CLKEXT;
} else {
dev_dbg(&adc->spi->dev,
"use crystal oscillator as clocksource\n");
configreg &= ~MCP3911_CONFIG_CLKEXT;
}
return mcp3911_write(adc, MCP3911_REG_CONFIG, configreg, 2);
}
static int mcp3911_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct mcp3911 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref");
if (IS_ERR(adc->vref)) {
if (PTR_ERR(adc->vref) == -ENODEV) {
adc->vref = NULL;
} else {
dev_err(&adc->spi->dev,
"failed to get regulator (%ld)\n",
PTR_ERR(adc->vref));
return PTR_ERR(adc->vref);
}
} else {
ret = regulator_enable(adc->vref);
if (ret)
return ret;
}
adc->clki = devm_clk_get(&adc->spi->dev, NULL);
if (IS_ERR(adc->clki)) {
if (PTR_ERR(adc->clki) == -ENOENT) {
adc->clki = NULL;
} else {
dev_err(&adc->spi->dev,
"failed to get adc clk (%ld)\n",
PTR_ERR(adc->clki));
ret = PTR_ERR(adc->clki);
goto reg_disable;
}
} else {
ret = clk_prepare_enable(adc->clki);
if (ret < 0) {
dev_err(&adc->spi->dev,
"Failed to enable clki: %d\n", ret);
goto reg_disable;
}
}
ret = mcp3911_config(adc, spi->dev.of_node);
if (ret)
goto clk_disable;
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;
indio_dev->info = &mcp3911_info;
spi_set_drvdata(spi, indio_dev);
indio_dev->channels = mcp3911_channels;
indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels);
mutex_init(&adc->lock);
ret = iio_device_register(indio_dev);
if (ret)
goto clk_disable;
return ret;
clk_disable:
clk_disable_unprepare(adc->clki);
reg_disable:
if (adc->vref)
regulator_disable(adc->vref);
return ret;
}
static int mcp3911_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct mcp3911 *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
clk_disable_unprepare(adc->clki);
if (adc->vref)
regulator_disable(adc->vref);
return 0;
}
static const struct of_device_id mcp3911_dt_ids[] = {
{ .compatible = "microchip,mcp3911" },
{ }
};
MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
static const struct spi_device_id mcp3911_id[] = {
{ "mcp3911", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp3911_id);
static struct spi_driver mcp3911_driver = {
.driver = {
.name = "mcp3911",
.of_match_table = mcp3911_dt_ids,
},
.probe = mcp3911_probe,
.remove = mcp3911_remove,
.id_table = mcp3911_id,
};
module_spi_driver(mcp3911_driver);
MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
MODULE_AUTHOR("Kent Gustavsson <kent@minoris.se>");
MODULE_DESCRIPTION("Microchip Technology MCP3911");
MODULE_LICENSE("GPL v2");
......@@ -708,8 +708,8 @@ static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
* mux.
*/
if (iiospec->args_count != 2) {
dev_err(&indio_dev->dev, "wrong number of arguments for %s need 2 got %d\n",
iiospec->np->name,
dev_err(&indio_dev->dev, "wrong number of arguments for %pOFn need 2 got %d\n",
iiospec->np,
iiospec->args_count);
return -EINVAL;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.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
#define ADC5_USR_STATUS1_REQ_STS BIT(1)
#define ADC5_USR_STATUS1_EOC BIT(0)
#define ADC5_USR_STATUS1_REQ_STS_EOC_MASK 0x3
#define ADC5_USR_STATUS2 0x9
#define ADC5_USR_STATUS2_CONV_SEQ_MASK 0x70
#define ADC5_USR_STATUS2_CONV_SEQ_MASK_SHIFT 0x5
#define ADC5_USR_IBAT_MEAS 0xf
#define ADC5_USR_IBAT_MEAS_SUPPORTED BIT(0)
#define ADC5_USR_DIG_PARAM 0x42
#define ADC5_USR_DIG_PARAM_CAL_VAL BIT(6)
#define ADC5_USR_DIG_PARAM_CAL_VAL_SHIFT 6
#define ADC5_USR_DIG_PARAM_CAL_SEL 0x30
#define ADC5_USR_DIG_PARAM_CAL_SEL_SHIFT 4
#define ADC5_USR_DIG_PARAM_DEC_RATIO_SEL 0xc
#define ADC5_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT 2
#define ADC5_USR_FAST_AVG_CTL 0x43
#define ADC5_USR_FAST_AVG_CTL_EN BIT(7)
#define ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK 0x7
#define ADC5_USR_CH_SEL_CTL 0x44
#define ADC5_USR_DELAY_CTL 0x45
#define ADC5_USR_HW_SETTLE_DELAY_MASK 0xf
#define ADC5_USR_EN_CTL1 0x46
#define ADC5_USR_EN_CTL1_ADC_EN BIT(7)
#define ADC5_USR_CONV_REQ 0x47
#define ADC5_USR_CONV_REQ_REQ BIT(7)
#define ADC5_USR_DATA0 0x50
#define ADC5_USR_DATA1 0x51
#define ADC5_USR_IBAT_DATA0 0x52
#define ADC5_USR_IBAT_DATA1 0x53
/*
* Conversion time varies based on the decimation, clock rate, fast average
* samples and measurements queued across different VADC peripherals.
* Set the timeout to a max of 100ms.
*/
#define ADC5_CONV_TIME_MIN_US 263
#define ADC5_CONV_TIME_MAX_US 264
#define ADC5_CONV_TIME_RETRY 400
#define ADC5_CONV_TIMEOUT msecs_to_jiffies(100)
/* Digital version >= 5.3 supports hw_settle_2 */
#define ADC5_HW_SETTLE_DIFF_MINOR 3
#define ADC5_HW_SETTLE_DIFF_MAJOR 5
enum adc5_cal_method {
ADC5_NO_CAL = 0,
ADC5_RATIOMETRIC_CAL,
ADC5_ABSOLUTE_CAL
};
enum adc5_cal_val {
ADC5_TIMER_CAL = 0,
ADC5_NEW_CAL
};
/**
* struct adc5_channel_prop - ADC channel property.
* @channel: channel number, refer to the channel list.
* @cal_method: calibration method.
* @cal_val: calibration value
* @decimation: sampling rate supported for the channel.
* @prescale: channel scaling performed on the input signal.
* @hw_settle_time: the time between AMUX being configured and the
* start of conversion.
* @avg_samples: ability to provide single result from the ADC
* that is an average of multiple measurements.
* @scale_fn_type: Represents the scaling function to convert voltage
* physical units desired by the client for the channel.
* @datasheet_name: Channel name used in device tree.
*/
struct adc5_channel_prop {
unsigned int channel;
enum adc5_cal_method cal_method;
enum adc5_cal_val cal_val;
unsigned int decimation;
unsigned int prescale;
unsigned int hw_settle_time;
unsigned int avg_samples;
enum vadc_scale_fn_type scale_fn_type;
const char *datasheet_name;
};
/**
* struct adc5_chip - ADC private structure.
* @regmap: SPMI ADC5 peripheral register map field.
* @dev: SPMI ADC5 device.
* @base: base address for the ADC peripheral.
* @nchannels: number of ADC channels.
* @chan_props: array of ADC channel properties.
* @iio_chans: array of IIO channels specification.
* @poll_eoc: use polling instead of interrupt.
* @complete: ADC result notification after interrupt is received.
* @lock: ADC lock for access to the peripheral.
* @data: software configuration data.
*/
struct adc5_chip {
struct regmap *regmap;
struct device *dev;
u16 base;
unsigned int nchannels;
struct adc5_channel_prop *chan_props;
struct iio_chan_spec *iio_chans;
bool poll_eoc;
struct completion complete;
struct mutex lock;
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);
}
static int adc5_write(struct adc5_chip *adc, u16 offset, u8 *data, int len)
{
return regmap_bulk_write(adc->regmap, adc->base + offset, data, len);
}
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;
u8 rslt_lsb, rslt_msb;
ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, sizeof(rslt_lsb));
if (ret)
return ret;
ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, sizeof(rslt_lsb));
if (ret)
return ret;
*data = (rslt_msb << 8) | rslt_lsb;
if (*data == ADC5_USR_DATA_CHECK) {
pr_err("Invalid data:0x%x\n", *data);
return -EINVAL;
}
pr_debug("voltage raw code:0x%x\n", *data);
return 0;
}
static int adc5_poll_wait_eoc(struct adc5_chip *adc)
{
unsigned int count, retry = ADC5_CONV_TIME_RETRY;
u8 status1;
int ret;
for (count = 0; count < retry; count++) {
ret = adc5_read(adc, ADC5_USR_STATUS1, &status1,
sizeof(status1));
if (ret)
return ret;
status1 &= ADC5_USR_STATUS1_REQ_STS_EOC_MASK;
if (status1 == ADC5_USR_STATUS1_EOC)
return 0;
usleep_range(ADC5_CONV_TIME_MIN_US, ADC5_CONV_TIME_MAX_US);
}
return -ETIMEDOUT;
}
static void adc5_update_dig_param(struct adc5_chip *adc,
struct adc5_channel_prop *prop, u8 *data)
{
/* Update calibration value */
*data &= ~ADC5_USR_DIG_PARAM_CAL_VAL;
*data |= (prop->cal_val << ADC5_USR_DIG_PARAM_CAL_VAL_SHIFT);
/* Update calibration select */
*data &= ~ADC5_USR_DIG_PARAM_CAL_SEL;
*data |= (prop->cal_method << ADC5_USR_DIG_PARAM_CAL_SEL_SHIFT);
/* Update decimation ratio select */
*data &= ~ADC5_USR_DIG_PARAM_DEC_RATIO_SEL;
*data |= (prop->decimation << ADC5_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT);
}
static int adc5_configure(struct adc5_chip *adc,
struct adc5_channel_prop *prop)
{
int ret;
u8 buf[6];
/* Read registers 0x42 through 0x46 */
ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
if (ret < 0)
return ret;
/* Digital param selection */
adc5_update_dig_param(adc, prop, &buf[0]);
/* Update fast average sample value */
buf[1] &= (u8) ~ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK;
buf[1] |= prop->avg_samples;
/* Select ADC channel */
buf[2] = prop->channel;
/* Select HW settle delay for channel */
buf[3] &= (u8) ~ADC5_USR_HW_SETTLE_DELAY_MASK;
buf[3] |= prop->hw_settle_time;
/* Select ADC enable */
buf[4] |= ADC5_USR_EN_CTL1_ADC_EN;
/* Select CONV request */
buf[5] |= ADC5_USR_CONV_REQ_REQ;
if (!adc->poll_eoc)
reinit_completion(&adc->complete);
return adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
}
static int adc5_do_conversion(struct adc5_chip *adc,
struct adc5_channel_prop *prop,
struct iio_chan_spec const *chan,
u16 *data_volt, u16 *data_cur)
{
int ret;
mutex_lock(&adc->lock);
ret = adc5_configure(adc, prop);
if (ret) {
pr_err("ADC configure failed with %d\n", ret);
goto unlock;
}
if (adc->poll_eoc) {
ret = adc5_poll_wait_eoc(adc);
if (ret < 0) {
pr_err("EOC bit not set\n");
goto unlock;
}
} else {
ret = wait_for_completion_timeout(&adc->complete,
ADC5_CONV_TIMEOUT);
if (!ret) {
pr_debug("Did not get completion timeout.\n");
ret = adc5_poll_wait_eoc(adc);
if (ret < 0) {
pr_err("EOC bit not set\n");
goto unlock;
}
}
}
ret = adc5_read_voltage_data(adc, data_volt);
unlock:
mutex_unlock(&adc->lock);
return ret;
}
static irqreturn_t adc5_isr(int irq, void *dev_id)
{
struct adc5_chip *adc = dev_id;
complete(&adc->complete);
return IRQ_HANDLED;
}
static int adc5_of_xlate(struct iio_dev *indio_dev,
const struct of_phandle_args *iiospec)
{
struct adc5_chip *adc = iio_priv(indio_dev);
int i;
for (i = 0; i < adc->nchannels; i++)
if (adc->chan_props[i].channel == iiospec->args[0])
return i;
return -EINVAL;
}
static int adc5_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
{
struct adc5_chip *adc = iio_priv(indio_dev);
struct adc5_channel_prop *prop;
u16 adc_code_volt, adc_code_cur;
int ret;
prop = &adc->chan_props[chan->address];
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
ret = adc5_do_conversion(adc, prop, chan,
&adc_code_volt, &adc_code_cur);
if (ret)
return ret;
ret = qcom_adc5_hw_scale(prop->scale_fn_type,
&adc5_prescale_ratios[prop->prescale],
adc->data,
adc_code_volt, val);
if (ret)
return ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
return 0;
}
static const struct iio_info adc5_info = {
.read_raw = adc5_read_raw,
.of_xlate = adc5_of_xlate,
};
struct adc5_channels {
const char *datasheet_name;
unsigned int prescale_index;
enum iio_chan_type type;
long info_mask;
enum vadc_scale_fn_type scale_fn_type;
};
#define ADC5_CHAN(_dname, _type, _mask, _pre, _scale) \
{ \
.datasheet_name = _dname, \
.prescale_index = _pre, \
.type = _type, \
.info_mask = _mask, \
.scale_fn_type = _scale, \
}, \
#define ADC5_CHAN_TEMP(_dname, _pre, _scale) \
ADC5_CHAN(_dname, IIO_TEMP, \
BIT(IIO_CHAN_INFO_PROCESSED), \
_pre, _scale) \
#define ADC5_CHAN_VOLT(_dname, _pre, _scale) \
ADC5_CHAN(_dname, IIO_VOLTAGE, \
BIT(IIO_CHAN_INFO_PROCESSED), \
_pre, _scale) \
static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
SCALE_HW_CALIB_PMIC_THERM)
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 16,
SCALE_HW_CALIB_DEFAULT)
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 1,
SCALE_HW_CALIB_PM5_CHG_TEMP)
/* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 6,
SCALE_HW_CALIB_DEFAULT)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1,
SCALE_HW_CALIB_XOTHERM)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 1,
SCALE_HW_CALIB_PM5_SMB_TEMP)
};
static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
SCALE_HW_CALIB_PMIC_THERM)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1,
SCALE_HW_CALIB_THERM_100K_PULLUP)
};
static int adc5_get_dt_channel_data(struct adc5_chip *adc,
struct adc5_channel_prop *prop,
struct device_node *node,
const struct adc5_data *data)
{
const char *name = node->name, *channel_name;
u32 chan, value, varr[2];
int ret;
struct device *dev = adc->dev;
ret = of_property_read_u32(node, "reg", &chan);
if (ret) {
dev_err(dev, "invalid channel number %s\n", name);
return ret;
}
if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA ||
!data->adc_chans[chan].datasheet_name) {
dev_err(dev, "%s invalid channel number %d\n", name, chan);
return -EINVAL;
}
/* the channel has DT description */
prop->channel = chan;
channel_name = of_get_property(node,
"label", NULL) ? : node->name;
if (!channel_name) {
pr_err("Invalid channel name\n");
return -EINVAL;
}
prop->datasheet_name = channel_name;
ret = of_property_read_u32(node, "qcom,decimation", &value);
if (!ret) {
ret = adc5_decimation_from_dt(value, data->decimation);
if (ret < 0) {
dev_err(dev, "%02x invalid decimation %d\n",
chan, value);
return ret;
}
prop->decimation = ret;
} else {
prop->decimation = ADC5_DECIMATION_DEFAULT;
}
ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
if (!ret) {
ret = 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]);
return ret;
}
prop->prescale = ret;
}
ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
if (!ret) {
u8 dig_version[2];
ret = adc5_read(adc, ADC5_USR_REVISION1, dig_version,
sizeof(dig_version));
if (ret < 0) {
dev_err(dev, "Invalid dig version read %d\n", ret);
return ret;
}
pr_debug("dig_ver:minor:%d, major:%d\n", dig_version[0],
dig_version[1]);
/* Digital controller >= 5.3 have hw_settle_2 option */
if (dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR &&
dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR)
ret = adc5_hw_settle_time_from_dt(value,
data->hw_settle_2);
else
ret = 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",
chan, value);
return ret;
}
prop->hw_settle_time = ret;
} else {
prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
}
ret = of_property_read_u32(node, "qcom,avg-samples", &value);
if (!ret) {
ret = adc5_avg_samples_from_dt(value);
if (ret < 0) {
dev_err(dev, "%02x invalid avg-samples %d\n",
chan, value);
return ret;
}
prop->avg_samples = ret;
} else {
prop->avg_samples = VADC_DEF_AVG_SAMPLES;
}
if (of_property_read_bool(node, "qcom,ratiometric"))
prop->cal_method = ADC5_RATIOMETRIC_CAL;
else
prop->cal_method = ADC5_ABSOLUTE_CAL;
/*
* Default to using timer calibration. Using a fresh calibration value
* for every conversion will increase the overall time for a request.
*/
prop->cal_val = ADC5_TIMER_CAL;
dev_dbg(dev, "%02x name %s\n", chan, name);
return 0;
}
static const struct adc5_data adc5_data_pmic = {
.full_scale_code_volt = 0x70e4,
.full_scale_code_cur = 0x2710,
.adc_chans = adc5_chans_pmic,
.decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
{250, 420, 840},
.hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
{15, 100, 200, 300, 400, 500, 600, 700,
800, 900, 1, 2, 4, 6, 8, 10},
.hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
{15, 100, 200, 300, 400, 500, 600, 700,
1, 2, 4, 8, 16, 32, 64, 128},
};
static const struct adc5_data adc5_data_pmic_rev2 = {
.full_scale_code_volt = 0x4000,
.full_scale_code_cur = 0x1800,
.adc_chans = adc5_chans_rev2,
.decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
{256, 512, 1024},
.hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
{0, 100, 200, 300, 400, 500, 600, 700,
800, 900, 1, 2, 4, 6, 8, 10},
.hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
{15, 100, 200, 300, 400, 500, 600, 700,
1, 2, 4, 8, 16, 32, 64, 128},
};
static const struct of_device_id adc5_match_table[] = {
{
.compatible = "qcom,spmi-adc5",
.data = &adc5_data_pmic,
},
{
.compatible = "qcom,spmi-adc-rev2",
.data = &adc5_data_pmic_rev2,
},
{ }
};
static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
{
const struct adc5_channels *adc_chan;
struct iio_chan_spec *iio_chan;
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);
if (!adc->nchannels)
return -EINVAL;
adc->iio_chans = devm_kcalloc(adc->dev, adc->nchannels,
sizeof(*adc->iio_chans), GFP_KERNEL);
if (!adc->iio_chans)
return -ENOMEM;
adc->chan_props = devm_kcalloc(adc->dev, adc->nchannels,
sizeof(*adc->chan_props), GFP_KERNEL);
if (!adc->chan_props)
return -ENOMEM;
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;
for_each_available_child_of_node(node, child) {
ret = adc5_get_dt_channel_data(adc, &prop, child, data);
if (ret) {
of_node_put(child);
return ret;
}
prop.scale_fn_type =
data->adc_chans[prop.channel].scale_fn_type;
*chan_props = prop;
adc_chan = &data->adc_chans[prop.channel];
iio_chan->channel = prop.channel;
iio_chan->datasheet_name = prop.datasheet_name;
iio_chan->extend_name = prop.datasheet_name;
iio_chan->info_mask_separate = adc_chan->info_mask;
iio_chan->type = adc_chan->type;
iio_chan->address = index;
iio_chan++;
chan_props++;
index++;
}
return 0;
}
static int adc5_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct iio_dev *indio_dev;
struct adc5_chip *adc;
struct regmap *regmap;
int ret, irq_eoc;
u32 reg;
regmap = dev_get_regmap(dev->parent, NULL);
if (!regmap)
return -ENODEV;
ret = of_property_read_u32(node, "reg", &reg);
if (ret < 0)
return ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->regmap = regmap;
adc->dev = dev;
adc->base = reg;
init_completion(&adc->complete);
mutex_init(&adc->lock);
ret = adc5_get_dt_data(adc, node);
if (ret) {
pr_err("adc get dt data failed\n");
return ret;
}
irq_eoc = platform_get_irq(pdev, 0);
if (irq_eoc < 0) {
if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
return irq_eoc;
adc->poll_eoc = true;
} else {
ret = devm_request_irq(dev, irq_eoc, adc5_isr, 0,
"pm-adc5", adc);
if (ret)
return ret;
}
indio_dev->dev.parent = dev;
indio_dev->dev.of_node = node;
indio_dev->name = pdev->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc5_info;
indio_dev->channels = adc->iio_chans;
indio_dev->num_channels = adc->nchannels;
return devm_iio_device_register(dev, indio_dev);
}
static struct platform_driver adc5_driver = {
.driver = {
.name = "qcom-spmi-adc5.c",
.of_match_table = adc5_match_table,
},
.probe = adc5_probe,
};
module_platform_driver(adc5_driver);
MODULE_ALIAS("platform:qcom-spmi-adc5");
MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 ADC driver");
MODULE_LICENSE("GPL v2");
......@@ -47,8 +47,79 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
{44, 125}
};
/*
* Voltage to temperature table for 100k pull up for NTCG104EF104 with
* 1.875V reference.
*/
static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
{ 1831, -40000 },
{ 1814, -35000 },
{ 1791, -30000 },
{ 1761, -25000 },
{ 1723, -20000 },
{ 1675, -15000 },
{ 1616, -10000 },
{ 1545, -5000 },
{ 1463, 0 },
{ 1370, 5000 },
{ 1268, 10000 },
{ 1160, 15000 },
{ 1049, 20000 },
{ 937, 25000 },
{ 828, 30000 },
{ 726, 35000 },
{ 630, 40000 },
{ 544, 45000 },
{ 467, 50000 },
{ 399, 55000 },
{ 340, 60000 },
{ 290, 65000 },
{ 247, 70000 },
{ 209, 75000 },
{ 179, 80000 },
{ 153, 85000 },
{ 130, 90000 },
{ 112, 95000 },
{ 96, 100000 },
{ 82, 105000 },
{ 71, 110000 },
{ 62, 115000 },
{ 53, 120000 },
{ 46, 125000 },
};
static int qcom_vadc_scale_hw_calib_volt(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_uv);
static int qcom_vadc_scale_hw_calib_therm(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec);
static int qcom_vadc_scale_hw_smb_temp(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec);
static int qcom_vadc_scale_hw_chg5_temp(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec);
static int qcom_vadc_scale_hw_calib_die_temp(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec);
static struct qcom_adc5_scale_type scale_adc5_fn[] = {
[SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
[SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
[SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
[SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
[SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
[SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
};
static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
u32 tablesize, s32 input, s64 *output)
u32 tablesize, s32 input, int *output)
{
bool descending = 1;
u32 i = 0;
......@@ -128,7 +199,7 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
bool absolute, u16 adc_code,
int *result_mdec)
{
s64 voltage = 0, result = 0;
s64 voltage = 0;
int ret;
qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
......@@ -138,12 +209,11 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
ARRAY_SIZE(adcmap_100k_104ef_104fb),
voltage, &result);
voltage, result_mdec);
if (ret)
return ret;
result *= 1000;
*result_mdec = result;
*result_mdec *= 1000;
return 0;
}
......@@ -191,6 +261,99 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
return 0;
}
static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
unsigned int factor)
{
s64 voltage, temp, adc_vdd_ref_mv = 1875;
/*
* The normal data range is between 0V to 1.875V. On cases where
* we read low voltage values, the ADC code can go beyond the
* range and the scale result is incorrect so we clamp the values
* for the cases where the code represents a value below 0V
*/
if (adc_code > VADC5_MAX_CODE)
adc_code = 0;
/* (ADC code * vref_vadc (1.875V)) / full_scale_code */
voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
voltage = div64_s64(voltage, data->full_scale_code_volt);
if (voltage > 0) {
voltage *= prescale->den;
temp = prescale->num * factor;
voltage = div64_s64(voltage, temp);
} else {
voltage = 0;
}
return (int) voltage;
}
static int qcom_vadc_scale_hw_calib_volt(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_uv)
{
*result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
prescale, data, 1);
return 0;
}
static int qcom_vadc_scale_hw_calib_therm(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec)
{
int voltage;
voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
prescale, data, 1000);
/* Map voltage to temperature from look-up table */
return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
voltage, result_mdec);
}
static int qcom_vadc_scale_hw_calib_die_temp(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec)
{
*result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
prescale, data, 2);
*result_mdec -= KELVINMIL_CELSIUSMIL;
return 0;
}
static int qcom_vadc_scale_hw_smb_temp(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec)
{
*result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
*result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
return 0;
}
static int qcom_vadc_scale_hw_chg5_temp(
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec)
{
*result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
prescale, data, 4);
*result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
return 0;
}
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
const struct vadc_linear_graph *calib_graph,
const struct vadc_prescale_ratio *prescale,
......@@ -221,6 +384,22 @@ 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,
const struct adc5_data *data,
u16 adc_code, int *result)
{
if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
scaletype < SCALE_HW_CALIB_INVALID)) {
pr_err("Invalid scale type %d\n", scaletype);
return -EINVAL;
}
return scale_adc5_fn[scaletype].scale_fn(prescale, data,
adc_code, result);
}
EXPORT_SYMBOL(qcom_adc5_hw_scale);
int qcom_vadc_decimation_from_dt(u32 value)
{
if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
......
......@@ -25,15 +25,31 @@
#define VADC_DECIMATION_MIN 512
#define VADC_DECIMATION_MAX 4096
#define ADC5_DEF_VBAT_PRESCALING 1 /* 1:3 */
#define ADC5_DECIMATION_SHORT 250
#define ADC5_DECIMATION_MEDIUM 420
#define ADC5_DECIMATION_LONG 840
/* Default decimation - 1024 for rev2, 840 for pmic5 */
#define ADC5_DECIMATION_DEFAULT 2
#define ADC5_DECIMATION_SAMPLES_MAX 3
#define VADC_HW_SETTLE_DELAY_MAX 10000
#define VADC_HW_SETTLE_SAMPLES_MAX 16
#define VADC_AVG_SAMPLES_MAX 512
#define ADC5_AVG_SAMPLES_MAX 16
#define KELVINMIL_CELSIUSMIL 273150
#define PMIC5_CHG_TEMP_SCALE_FACTOR 377500
#define PMIC5_SMB_TEMP_CONSTANT 419400
#define PMIC5_SMB_TEMP_SCALE_FACTOR 356
#define PMI_CHG_SCALE_1 -138890
#define PMI_CHG_SCALE_2 391750000000LL
#define VADC5_MAX_CODE 0x7fff
#define ADC5_FULL_SCALE_CODE 0x70e4
#define ADC5_USR_DATA_CHECK 0x8000
/**
* struct vadc_map_pt - Map the graph representation for ADC channel
* @x: Represent the ADC digitized code.
......@@ -89,6 +105,18 @@ struct vadc_prescale_ratio {
* SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
* SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
* SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
* SCALE_HW_CALIB_DEFAULT: Default scaling to convert raw adc code to
* voltage (uV) with hardware applied offset/slope values to adc code.
* SCALE_HW_CALIB_THERM_100K_PULLUP: Returns temperature in millidegC using
* lookup table. The hardware applies offset/slope to adc code.
* SCALE_HW_CALIB_XOTHERM: Returns XO thermistor voltage in millidegC using
* 100k pullup. The hardware applies offset/slope to adc code.
* SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade.
* The hardware applies offset/slope to adc code.
* SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5
* charger temperature.
* SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5
* SMB1390 temperature.
*/
enum vadc_scale_fn_type {
SCALE_DEFAULT = 0,
......@@ -96,6 +124,22 @@ enum vadc_scale_fn_type {
SCALE_PMIC_THERM,
SCALE_XOTHERM,
SCALE_PMI_CHG_TEMP,
SCALE_HW_CALIB_DEFAULT,
SCALE_HW_CALIB_THERM_100K_PULLUP,
SCALE_HW_CALIB_XOTHERM,
SCALE_HW_CALIB_PMIC_THERM,
SCALE_HW_CALIB_PM5_CHG_TEMP,
SCALE_HW_CALIB_PM5_SMB_TEMP,
SCALE_HW_CALIB_INVALID,
};
struct adc5_data {
const u32 full_scale_code_volt;
const u32 full_scale_code_cur;
const struct adc5_channels *adc_chans;
unsigned int *decimation;
unsigned int *hw_settle_1;
unsigned int *hw_settle_2;
};
int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
......@@ -104,6 +148,16 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
bool absolute,
u16 adc_code, int *result_mdec);
struct qcom_adc5_scale_type {
int (*scale_fn)(const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data, u16 adc_code, int *result);
};
int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
const struct vadc_prescale_ratio *prescale,
const struct adc5_data *data,
u16 adc_code, int *result_mdec);
int qcom_vadc_decimation_from_dt(u32 value);
#endif /* QCOM_VADC_COMMON_H */
......@@ -343,8 +343,8 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
for_each_child_of_node(np, child) {
of_id = of_match_node(rcar_gyroadc_child_match, child);
if (!of_id) {
dev_err(dev, "Ignoring unsupported ADC \"%s\".",
child->name);
dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".",
child);
continue;
}
......@@ -381,16 +381,16 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
ret = of_property_read_u32(child, "reg", &reg);
if (ret) {
dev_err(dev,
"Failed to get child reg property of ADC \"%s\".\n",
child->name);
"Failed to get child reg property of ADC \"%pOFn\".\n",
child);
return ret;
}
/* Channel number is too high. */
if (reg >= num_channels) {
dev_err(dev,
"Only %i channels supported with %s, but reg = <%i>.\n",
num_channels, child->name, reg);
"Only %i channels supported with %pOFn, but reg = <%i>.\n",
num_channels, child, reg);
return ret;
}
}
......
......@@ -5,10 +5,12 @@
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
/* PMIC global registers definition */
#define SC27XX_MODULE_EN 0xc08
......@@ -87,16 +89,73 @@ struct sc27xx_adc_linear_graph {
* should use the small-scale graph, and if more than 1.2v, we should use the
* big-scale graph.
*/
static const struct sc27xx_adc_linear_graph big_scale_graph = {
static struct sc27xx_adc_linear_graph big_scale_graph = {
4200, 3310,
3600, 2832,
};
static const struct sc27xx_adc_linear_graph small_scale_graph = {
static struct sc27xx_adc_linear_graph small_scale_graph = {
1000, 3413,
100, 341,
};
static const struct sc27xx_adc_linear_graph big_scale_graph_calib = {
4200, 856,
3600, 733,
};
static const struct sc27xx_adc_linear_graph small_scale_graph_calib = {
1000, 833,
100, 80,
};
static int sc27xx_adc_get_calib_data(u32 calib_data, int calib_adc)
{
return ((calib_data & 0xff) + calib_adc - 128) * 4;
}
static int sc27xx_adc_scale_calibration(struct sc27xx_adc_data *data,
bool big_scale)
{
const struct sc27xx_adc_linear_graph *calib_graph;
struct sc27xx_adc_linear_graph *graph;
struct nvmem_cell *cell;
const char *cell_name;
u32 calib_data = 0;
void *buf;
size_t len;
if (big_scale) {
calib_graph = &big_scale_graph_calib;
graph = &big_scale_graph;
cell_name = "big_scale_calib";
} else {
calib_graph = &small_scale_graph_calib;
graph = &small_scale_graph;
cell_name = "small_scale_calib";
}
cell = nvmem_cell_get(data->dev, cell_name);
if (IS_ERR(cell))
return PTR_ERR(cell);
buf = nvmem_cell_read(cell, &len);
nvmem_cell_put(cell);
if (IS_ERR(buf))
return PTR_ERR(buf);
memcpy(&calib_data, buf, min(len, sizeof(u32)));
/* Only need to calibrate the adc values in the linear graph. */
graph->adc0 = sc27xx_adc_get_calib_data(calib_data, calib_graph->adc0);
graph->adc1 = sc27xx_adc_get_calib_data(calib_data >> 8,
calib_graph->adc1);
kfree(buf);
return 0;
}
static int sc27xx_adc_get_ratio(int channel, int scale)
{
switch (channel) {
......@@ -209,7 +268,7 @@ static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
*div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK;
}
static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph,
static int sc27xx_adc_to_volt(struct sc27xx_adc_linear_graph *graph,
int raw_adc)
{
int tmp;
......@@ -273,6 +332,17 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
int ret, tmp;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
*val = tmp;
return IIO_VAL_INT;
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
......@@ -315,48 +385,47 @@ static const struct iio_info sc27xx_info = {
.write_raw = &sc27xx_adc_write_raw,
};
#define SC27XX_ADC_CHANNEL(index) { \
#define SC27XX_ADC_CHANNEL(index, mask) { \
.type = IIO_VOLTAGE, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_separate = mask | BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "CH##index", \
.indexed = 1, \
}
static const struct iio_chan_spec sc27xx_channels[] = {
SC27XX_ADC_CHANNEL(0),
SC27XX_ADC_CHANNEL(1),
SC27XX_ADC_CHANNEL(2),
SC27XX_ADC_CHANNEL(3),
SC27XX_ADC_CHANNEL(4),
SC27XX_ADC_CHANNEL(5),
SC27XX_ADC_CHANNEL(6),
SC27XX_ADC_CHANNEL(7),
SC27XX_ADC_CHANNEL(8),
SC27XX_ADC_CHANNEL(9),
SC27XX_ADC_CHANNEL(10),
SC27XX_ADC_CHANNEL(11),
SC27XX_ADC_CHANNEL(12),
SC27XX_ADC_CHANNEL(13),
SC27XX_ADC_CHANNEL(14),
SC27XX_ADC_CHANNEL(15),
SC27XX_ADC_CHANNEL(16),
SC27XX_ADC_CHANNEL(17),
SC27XX_ADC_CHANNEL(18),
SC27XX_ADC_CHANNEL(19),
SC27XX_ADC_CHANNEL(20),
SC27XX_ADC_CHANNEL(21),
SC27XX_ADC_CHANNEL(22),
SC27XX_ADC_CHANNEL(23),
SC27XX_ADC_CHANNEL(24),
SC27XX_ADC_CHANNEL(25),
SC27XX_ADC_CHANNEL(26),
SC27XX_ADC_CHANNEL(27),
SC27XX_ADC_CHANNEL(28),
SC27XX_ADC_CHANNEL(29),
SC27XX_ADC_CHANNEL(30),
SC27XX_ADC_CHANNEL(31),
SC27XX_ADC_CHANNEL(0, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(1, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(2, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(3, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(4, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(5, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(6, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(7, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(8, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(9, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(10, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(11, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(12, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(13, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(14, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(15, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(16, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(17, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(18, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(19, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(20, BIT(IIO_CHAN_INFO_RAW)),
SC27XX_ADC_CHANNEL(21, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(22, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(23, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(24, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(25, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(26, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(27, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(28, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(29, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(30, BIT(IIO_CHAN_INFO_PROCESSED)),
SC27XX_ADC_CHANNEL(31, BIT(IIO_CHAN_INFO_PROCESSED)),
};
static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
......@@ -380,6 +449,15 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
if (ret)
goto disable_clk;
/* ADC channel scales' calibration from nvmem device */
ret = sc27xx_adc_scale_calibration(data, true);
if (ret)
goto disable_clk;
ret = sc27xx_adc_scale_calibration(data, false);
if (ret)
goto disable_clk;
return 0;
disable_clk:
......
......@@ -209,6 +209,6 @@ static struct spi_driver ad8366_driver = {
module_spi_driver(ad8366_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
MODULE_LICENSE("GPL v2");
......@@ -4,10 +4,10 @@
#define BME680_REG_CHIP_I2C_ID 0xD0
#define BME680_REG_CHIP_SPI_ID 0x50
#define BME680_CHIP_ID_VAL 0x61
#define BME680_CHIP_ID_VAL 0x61
#define BME680_REG_SOFT_RESET_I2C 0xE0
#define BME680_REG_SOFT_RESET_SPI 0x60
#define BME680_CMD_SOFTRESET 0xB6
#define BME680_CMD_SOFTRESET 0xB6
#define BME680_REG_STATUS 0x73
#define BME680_SPI_MEM_PAGE_BIT BIT(4)
#define BME680_SPI_MEM_PAGE_1_VAL 1
......@@ -18,6 +18,7 @@
#define BME680_REG_GAS_MSB 0x2A
#define BME680_REG_GAS_R_LSB 0x2B
#define BME680_GAS_STAB_BIT BIT(4)
#define BME680_GAS_RANGE_MASK GENMASK(3, 0)
#define BME680_REG_CTRL_HUMIDITY 0x72
#define BME680_OSRS_HUMIDITY_MASK GENMASK(2, 0)
......@@ -26,9 +27,8 @@
#define BME680_OSRS_TEMP_MASK GENMASK(7, 5)
#define BME680_OSRS_PRESS_MASK GENMASK(4, 2)
#define BME680_MODE_MASK GENMASK(1, 0)
#define BME680_MODE_FORCED 1
#define BME680_MODE_SLEEP 0
#define BME680_MODE_FORCED 1
#define BME680_MODE_SLEEP 0
#define BME680_REG_CONFIG 0x75
#define BME680_FILTER_MASK GENMASK(4, 2)
......@@ -39,24 +39,21 @@
#define BME680_MAX_OVERFLOW_VAL 0x40000000
#define BME680_HUM_REG_SHIFT_VAL 4
#define BME680_BIT_H1_DATA_MSK 0x0F
#define BME680_BIT_H1_DATA_MASK GENMASK(3, 0)
#define BME680_REG_RES_HEAT_RANGE 0x02
#define BME680_RHRANGE_MSK 0x30
#define BME680_RHRANGE_MASK GENMASK(5, 4)
#define BME680_REG_RES_HEAT_VAL 0x00
#define BME680_REG_RANGE_SW_ERR 0x04
#define BME680_RSERROR_MSK 0xF0
#define BME680_RSERROR_MASK GENMASK(7, 4)
#define BME680_REG_RES_HEAT_0 0x5A
#define BME680_REG_GAS_WAIT_0 0x64
#define BME680_GAS_RANGE_MASK 0x0F
#define BME680_ADC_GAS_RES_SHIFT 6
#define BME680_AMB_TEMP 25
#define BME680_REG_CTRL_GAS_1 0x71
#define BME680_RUN_GAS_MASK BIT(4)
#define BME680_NB_CONV_MASK GENMASK(3, 0)
#define BME680_RUN_GAS_EN_BIT BIT(4)
#define BME680_NB_CONV_0_VAL 0
#define BME680_REG_MEAS_STAT_0 0x1D
#define BME680_GAS_MEAS_BIT BIT(6)
......
......@@ -91,8 +91,6 @@ static const struct iio_chan_spec bme680_channels[] = {
},
};
static const int bme680_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static int bme680_read_calib(struct bme680_data *data,
struct bme680_calib *calib)
{
......@@ -102,16 +100,14 @@ static int bme680_read_calib(struct bme680_data *data,
__le16 buf;
/* Temperature related coefficients */
ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T1_LSB_REG\n");
return ret;
}
calib->par_t1 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T2_LSB_REG\n");
return ret;
......@@ -126,16 +122,14 @@ static int bme680_read_calib(struct bme680_data *data,
calib->par_t3 = tmp;
/* Pressure related coefficients */
ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P1_LSB_REG\n");
return ret;
}
calib->par_p1 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P2_LSB_REG\n");
return ret;
......@@ -149,16 +143,14 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_p3 = tmp;
ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P4_LSB_REG\n");
return ret;
}
calib->par_p4 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P5_LSB_REG\n");
return ret;
......@@ -179,16 +171,14 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_p7 = tmp;
ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P8_LSB_REG\n");
return ret;
}
calib->par_p8 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P9_LSB_REG\n");
return ret;
......@@ -208,30 +198,26 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read BME680_H1_MSB_REG\n");
return ret;
}
ret = regmap_read(data->regmap, BME680_H1_LSB_REG, &tmp_lsb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H1_LSB_REG\n");
return ret;
}
calib->par_h1 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
(tmp_lsb & BME680_BIT_H1_DATA_MSK);
(tmp_lsb & BME680_BIT_H1_DATA_MASK);
ret = regmap_read(data->regmap, BME680_H2_MSB_REG, &tmp_msb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H2_MSB_REG\n");
return ret;
}
ret = regmap_read(data->regmap, BME680_H2_LSB_REG, &tmp_lsb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H2_LSB_REG\n");
return ret;
}
calib->par_h2 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
(tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
(tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
ret = regmap_read(data->regmap, BME680_H3_REG, &tmp);
if (ret < 0) {
......@@ -276,8 +262,8 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_gh1 = tmp;
ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG, (u8 *) &buf,
2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_GH2_LSB_REG\n");
return ret;
......@@ -297,7 +283,7 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read resistance heat range\n");
return ret;
}
calib->res_heat_range = (tmp & BME680_RHRANGE_MSK) / 16;
calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, tmp);
ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_VAL, &tmp);
if (ret < 0) {
......@@ -311,7 +297,7 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read range software error\n");
return ret;
}
calib->range_sw_err = (tmp & BME680_RSERROR_MSK) / 16;
calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, tmp);
return 0;
}
......@@ -408,10 +394,7 @@ static u32 bme680_compensate_humid(struct bme680_data *data,
var6 = (var4 * var5) >> 1;
calc_hum = (((var3 + var6) >> 10) * 1000) >> 12;
if (calc_hum > 100000) /* Cap at 100%rH */
calc_hum = 100000;
else if (calc_hum < 0)
calc_hum = 0;
calc_hum = clamp(calc_hum, 0, 100000); /* clamp between 0-100 %rH */
return calc_hum;
}
......@@ -518,12 +501,20 @@ static int bme680_set_mode(struct bme680_data *data, bool mode)
return ret;
}
static u8 bme680_oversampling_to_reg(u8 val)
{
return ilog2(val) + 1;
}
static int bme680_chip_config(struct bme680_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
u8 osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK,
data->oversampling_humid + 1);
u8 osrs;
osrs = FIELD_PREP(
BME680_OSRS_HUMIDITY_MASK,
bme680_oversampling_to_reg(data->oversampling_humid));
/*
* Highly recommended to set oversampling of humidity before
* temperature/pressure oversampling.
......@@ -544,12 +535,12 @@ static int bme680_chip_config(struct bme680_data *data)
return ret;
}
osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BME680_OSRS_PRESS_MASK, data->oversampling_press + 1);
osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK,
bme680_oversampling_to_reg(data->oversampling_temp)) |
FIELD_PREP(BME680_OSRS_PRESS_MASK,
bme680_oversampling_to_reg(data->oversampling_press));
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_OSRS_TEMP_MASK |
BME680_OSRS_PRESS_MASK,
BME680_OSRS_TEMP_MASK | BME680_OSRS_PRESS_MASK,
osrs);
if (ret < 0)
dev_err(dev, "failed to write ctrl_meas register\n");
......@@ -577,14 +568,15 @@ static int bme680_gas_config(struct bme680_data *data)
/* set target heating duration */
ret = regmap_write(data->regmap, BME680_REG_GAS_WAIT_0, heatr_dur);
if (ret < 0) {
dev_err(dev, "failted to write gas_wait_0 register\n");
dev_err(dev, "failed to write gas_wait_0 register\n");
return ret;
}
/* Selecting the runGas and NB conversion settings for the sensor */
/* Enable the gas sensor and select heater profile set-point 0 */
ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1,
BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK,
BME680_RUN_GAS_EN_BIT | BME680_NB_CONV_0_VAL);
FIELD_PREP(BME680_RUN_GAS_MASK, 1) |
FIELD_PREP(BME680_NB_CONV_MASK, 0));
if (ret < 0)
dev_err(dev, "failed to write ctrl_gas_1 register\n");
......@@ -782,13 +774,13 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_TEMP:
*val = 1 << data->oversampling_temp;
*val = data->oversampling_temp;
return IIO_VAL_INT;
case IIO_PRESSURE:
*val = 1 << data->oversampling_press;
*val = data->oversampling_press;
return IIO_VAL_INT;
case IIO_HUMIDITYRELATIVE:
*val = 1 << data->oversampling_humid;
*val = data->oversampling_humid;
return IIO_VAL_INT;
default:
return -EINVAL;
......@@ -798,52 +790,9 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
}
}
static int bme680_write_oversampling_ratio_temp(struct bme680_data *data,
int val)
{
int i;
for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
if (bme680_oversampling_avail[i] == val) {
data->oversampling_temp = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
}
static int bme680_write_oversampling_ratio_press(struct bme680_data *data,
int val)
{
int i;
for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
if (bme680_oversampling_avail[i] == val) {
data->oversampling_press = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
}
static int bme680_write_oversampling_ratio_humid(struct bme680_data *data,
int val)
static bool bme680_is_valid_oversampling(int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
if (bme680_oversampling_avail[i] == val) {
data->oversampling_humid = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
return (rate > 0 && rate <= 16 && is_power_of_2(rate));
}
static int bme680_write_raw(struct iio_dev *indio_dev,
......@@ -852,18 +801,31 @@ static int bme680_write_raw(struct iio_dev *indio_dev,
{
struct bme680_data *data = iio_priv(indio_dev);
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
{
if (!bme680_is_valid_oversampling(val))
return -EINVAL;
switch (chan->type) {
case IIO_TEMP:
return bme680_write_oversampling_ratio_temp(data, val);
data->oversampling_temp = val;
break;
case IIO_PRESSURE:
return bme680_write_oversampling_ratio_press(data, val);
data->oversampling_press = val;
break;
case IIO_HUMIDITYRELATIVE:
return bme680_write_oversampling_ratio_humid(data, val);
data->oversampling_humid = val;
break;
default:
return -EINVAL;
}
return bme680_chip_config(data);
}
default:
return -EINVAL;
}
......@@ -925,9 +887,9 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
/* default values for the sensor */
data->oversampling_humid = ilog2(2); /* 2X oversampling rate */
data->oversampling_press = ilog2(4); /* 4X oversampling rate */
data->oversampling_temp = ilog2(8); /* 8X oversampling rate */
data->oversampling_humid = 2; /* 2X oversampling rate */
data->oversampling_press = 4; /* 4X oversampling rate */
data->oversampling_temp = 8; /* 8X oversampling rate */
data->heater_temp = 320; /* degree Celsius */
data->heater_dur = 150; /* milliseconds */
......
......@@ -120,6 +120,16 @@ config AD5624R_SPI
Say yes here to build support for Analog Devices AD5624R, AD5644R and
AD5664R converters (DAC). This driver uses the common SPI interface.
config LTC1660
tristate "Linear Technology LTC1660/LTC1665 DAC SPI driver"
depends on SPI
help
Say yes here to build support for Linear Technology
LTC1660 and LTC1665 Digital to Analog Converters.
To compile this driver as a module, choose M here: the
module will be called ltc1660.
config LTC2632
tristate "Linear Technology LTC2632-12/10/8 DAC spi driver"
depends on SPI
......
......@@ -29,6 +29,7 @@ obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
obj-$(CONFIG_DS4424) += ds4424.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_LTC1660) += ltc1660.o
obj-$(CONFIG_LTC2632) += ltc2632.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
......
......@@ -628,6 +628,6 @@ static void __exit ad5446_exit(void)
}
module_exit(ad5446_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
MODULE_LICENSE("GPL v2");
......@@ -369,6 +369,6 @@ static struct spi_driver ad5504_driver = {
};
module_spi_driver(ad5504_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
MODULE_LICENSE("GPL v2");
......@@ -470,6 +470,6 @@ int ad5686_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(ad5686_remove);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
MODULE_LICENSE("GPL v2");
......@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
......@@ -108,6 +109,7 @@ struct ad5758_range {
struct ad5758_state {
struct spi_device *spi;
struct mutex lock;
struct gpio_desc *gpio_reset;
struct ad5758_range out_range;
unsigned int dc_dc_mode;
unsigned int dc_dc_ilim;
......@@ -474,6 +476,21 @@ static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable)
AD5758_CAL_MEM_UNREFRESHED_MSK);
}
static int ad5758_reset(struct ad5758_state *st)
{
if (st->gpio_reset) {
gpiod_set_value(st->gpio_reset, 0);
usleep_range(100, 1000);
gpiod_set_value(st->gpio_reset, 1);
usleep_range(100, 1000);
return 0;
} else {
/* Perform a software reset */
return ad5758_soft_reset(st);
}
}
static int ad5758_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
......@@ -768,13 +785,18 @@ static int ad5758_init(struct ad5758_state *st)
{
int regval, ret;
st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(st->gpio_reset))
return PTR_ERR(st->gpio_reset);
/* Disable CRC checks */
ret = ad5758_crc_disable(st);
if (ret < 0)
return ret;
/* Perform a software reset */
ret = ad5758_soft_reset(st);
/* Perform a reset */
ret = ad5758_reset(st);
if (ret < 0)
return ret;
......
......@@ -467,6 +467,6 @@ static struct spi_driver ad5791_driver = {
};
module_spi_driver(ad5791_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* IIO DAC emulation driver using a digital potentiometer
*
* Copyright (C) 2016 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Linear Technology LTC1665/LTC1660, 8 channels DAC
*
* Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
*/
#include <linux/bitops.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#define LTC1660_REG_WAKE 0x0
#define LTC1660_REG_DAC_A 0x1
#define LTC1660_REG_DAC_B 0x2
#define LTC1660_REG_DAC_C 0x3
#define LTC1660_REG_DAC_D 0x4
#define LTC1660_REG_DAC_E 0x5
#define LTC1660_REG_DAC_F 0x6
#define LTC1660_REG_DAC_G 0x7
#define LTC1660_REG_DAC_H 0x8
#define LTC1660_REG_SLEEP 0xe
#define LTC1660_NUM_CHANNELS 8
static const struct regmap_config ltc1660_regmap_config = {
.reg_bits = 4,
.val_bits = 12,
};
enum ltc1660_supported_device_ids {
ID_LTC1660,
ID_LTC1665,
};
struct ltc1660_priv {
struct spi_device *spi;
struct regmap *regmap;
struct regulator *vref_reg;
unsigned int value[LTC1660_NUM_CHANNELS];
unsigned int vref_mv;
};
static int ltc1660_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct ltc1660_priv *priv = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
*val = priv->value[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = regulator_get_voltage(priv->vref_reg);
if (*val < 0) {
dev_err(&priv->spi->dev, "failed to read vref regulator: %d\n",
*val);
return *val;
}
/* Convert to mV */
*val /= 1000;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static int ltc1660_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long mask)
{
struct ltc1660_priv *priv = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val2 != 0)
return -EINVAL;
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
ret = regmap_write(priv->regmap, chan->channel,
(val << chan->scan_type.shift));
if (!ret)
priv->value[chan->channel] = val;
return ret;
default:
return -EINVAL;
}
}
#define LTC1660_CHAN(chan, bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = 12 - (bits), \
}, \
}
#define LTC1660_OCTAL_CHANNELS(bits) { \
LTC1660_CHAN(LTC1660_REG_DAC_A, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_B, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_C, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_D, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_E, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_F, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_G, bits), \
LTC1660_CHAN(LTC1660_REG_DAC_H, bits), \
}
static const struct iio_chan_spec ltc1660_channels[][LTC1660_NUM_CHANNELS] = {
[ID_LTC1660] = LTC1660_OCTAL_CHANNELS(10),
[ID_LTC1665] = LTC1660_OCTAL_CHANNELS(8),
};
static const struct iio_info ltc1660_info = {
.read_raw = &ltc1660_read_raw,
.write_raw = &ltc1660_write_raw,
};
static int __maybe_unused ltc1660_suspend(struct device *dev)
{
struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(
to_spi_device(dev)));
return regmap_write(priv->regmap, LTC1660_REG_SLEEP, 0x00);
}
static int __maybe_unused ltc1660_resume(struct device *dev)
{
struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(
to_spi_device(dev)));
return regmap_write(priv->regmap, LTC1660_REG_WAKE, 0x00);
}
static SIMPLE_DEV_PM_OPS(ltc1660_pm_ops, ltc1660_suspend, ltc1660_resume);
static int ltc1660_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ltc1660_priv *priv;
const struct spi_device_id *id = spi_get_device_id(spi);
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
if (indio_dev == NULL)
return -ENOMEM;
priv = iio_priv(indio_dev);
priv->regmap = devm_regmap_init_spi(spi, &ltc1660_regmap_config);
if (IS_ERR(priv->regmap)) {
dev_err(&spi->dev, "failed to register spi regmap %ld\n",
PTR_ERR(priv->regmap));
return PTR_ERR(priv->regmap);
}
priv->vref_reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(priv->vref_reg)) {
dev_err(&spi->dev, "vref regulator not specified\n");
return PTR_ERR(priv->vref_reg);
}
ret = regulator_enable(priv->vref_reg);
if (ret) {
dev_err(&spi->dev, "failed to enable vref regulator: %d\n",
ret);
return ret;
}
priv->spi = spi;
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ltc1660_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ltc1660_channels[id->driver_data];
indio_dev->num_channels = LTC1660_NUM_CHANNELS;
indio_dev->name = id->name;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "failed to register iio device: %d\n",
ret);
goto error_disable_reg;
}
return 0;
error_disable_reg:
regulator_disable(priv->vref_reg);
return ret;
}
static int ltc1660_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ltc1660_priv *priv = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(priv->vref_reg);
return 0;
}
static const struct of_device_id ltc1660_dt_ids[] = {
{ .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 },
{ .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);
static const struct spi_device_id ltc1660_id[] = {
{"ltc1660", ID_LTC1660},
{"ltc1665", ID_LTC1665},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(spi, ltc1660_id);
static struct spi_driver ltc1660_driver = {
.driver = {
.name = "ltc1660",
.of_match_table = ltc1660_dt_ids,
.pm = &ltc1660_pm_ops,
},
.probe = ltc1660_probe,
.remove = ltc1660_remove,
.id_table = ltc1660_id,
};
module_spi_driver(ltc1660_driver);
MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
MODULE_DESCRIPTION("Linear Technology LTC1660/LTC1665 DAC");
MODULE_LICENSE("GPL v2");
......@@ -113,15 +113,14 @@ static int max517_write_raw(struct iio_dev *indio_dev,
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int max517_suspend(struct device *dev)
static int __maybe_unused max517_suspend(struct device *dev)
{
u8 outbuf = COMMAND_PD;
return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
}
static int max517_resume(struct device *dev)
static int __maybe_unused max517_resume(struct device *dev)
{
u8 outbuf = 0;
......@@ -129,10 +128,6 @@ static int max517_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
#define MAX517_PM_OPS (&max517_pm_ops)
#else
#define MAX517_PM_OPS NULL
#endif
static const struct iio_info max517_info = {
.read_raw = max517_read_raw,
......@@ -229,7 +224,7 @@ MODULE_DEVICE_TABLE(i2c, max517_id);
static struct i2c_driver max517_driver = {
.driver = {
.name = MAX517_DRV_NAME,
.pm = MAX517_PM_OPS,
.pm = &max517_pm_ops,
},
.probe = max517_probe,
.remove = max517_remove,
......
......@@ -270,8 +270,7 @@ static int max5821_write_raw(struct iio_dev *indio_dev,
}
}
#ifdef CONFIG_PM_SLEEP
static int max5821_suspend(struct device *dev)
static int __maybe_unused max5821_suspend(struct device *dev)
{
u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
MAX5821_EXTENDED_DAC_A |
......@@ -281,7 +280,7 @@ static int max5821_suspend(struct device *dev)
return i2c_master_send(to_i2c_client(dev), outbuf, 2);
}
static int max5821_resume(struct device *dev)
static int __maybe_unused max5821_resume(struct device *dev)
{
u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
MAX5821_EXTENDED_DAC_A |
......@@ -292,10 +291,6 @@ static int max5821_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume);
#define MAX5821_PM_OPS (&max5821_pm_ops)
#else
#define MAX5821_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static const struct iio_info max5821_info = {
.read_raw = max5821_read_raw,
......@@ -392,7 +387,7 @@ static struct i2c_driver max5821_driver = {
.driver = {
.name = "max5821",
.of_match_table = max5821_of_match,
.pm = MAX5821_PM_OPS,
.pm = &max5821_pm_ops,
},
.probe = max5821_probe,
.remove = max5821_remove,
......
......@@ -45,7 +45,7 @@ struct mcp4725_data {
struct regulator *vref_reg;
};
static int mcp4725_suspend(struct device *dev)
static int __maybe_unused mcp4725_suspend(struct device *dev)
{
struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
......@@ -58,7 +58,7 @@ static int mcp4725_suspend(struct device *dev)
return i2c_master_send(data->client, outbuf, 2);
}
static int mcp4725_resume(struct device *dev)
static int __maybe_unused mcp4725_resume(struct device *dev)
{
struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
......@@ -71,13 +71,7 @@ static int mcp4725_resume(struct device *dev)
return i2c_master_send(data->client, outbuf, 2);
}
#ifdef CONFIG_PM_SLEEP
static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
#define MCP4725_PM_OPS (&mcp4725_pm_ops)
#else
#define MCP4725_PM_OPS NULL
#endif
static ssize_t mcp4725_store_eeprom(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
......@@ -547,7 +541,7 @@ static struct i2c_driver mcp4725_driver = {
.driver = {
.name = MCP4725_DRV_NAME,
.of_match_table = of_match_ptr(mcp4725_of_match),
.pm = MCP4725_PM_OPS,
.pm = &mcp4725_pm_ops,
},
.probe = mcp4725_probe,
.remove = mcp4725_remove,
......
......@@ -94,17 +94,22 @@ static int mcp4922_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct mcp4922_state *state = iio_priv(indio_dev);
int ret;
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val > GENMASK(chan->scan_type.realbits-1, 0))
if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL;
val <<= chan->scan_type.shift;
state->value[chan->channel] = val;
return mcp4922_spi_write(state, chan->channel, val);
ret = mcp4922_spi_write(state, chan->channel, val);
if (!ret)
state->value[chan->channel] = val;
return ret;
default:
return -EINVAL;
}
......
......@@ -421,6 +421,7 @@ MODULE_DEVICE_TABLE(i2c, dac5571_id);
static struct i2c_driver dac5571_driver = {
.driver = {
.name = "ti-dac5571",
.of_match_table = of_match_ptr(dac5571_of_id),
},
.probe = dac5571_probe,
.remove = dac5571_remove,
......
......@@ -1078,6 +1078,6 @@ static struct spi_driver ad9523_driver = {
};
module_spi_driver(ad9523_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9523 CLOCKDIST/PLL");
MODULE_LICENSE("GPL v2");
......@@ -388,7 +388,7 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
if (!pdata)
return NULL;
strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
snprintf(&pdata->name[0], SPI_NAME_SIZE - 1, "%pOFn", np);
tmp = 10000;
of_property_read_u32(np, "adi,channel-spacing", &tmp);
......
......@@ -282,9 +282,11 @@ static int max30102_read_measurement(struct max30102_data *data,
switch (measurements) {
case 3:
MAX30102_COPY_DATA(2);
case 2: /* fall-through */
/* fall through */
case 2:
MAX30102_COPY_DATA(1);
case 1: /* fall-through */
/* fall through */
case 1:
MAX30102_COPY_DATA(0);
break;
default:
......
......@@ -23,6 +23,7 @@
#include <linux/iio/iio.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include "inv_mpu_iio.h"
/*
......@@ -926,6 +927,39 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
return result;
}
static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
{
int result;
result = regulator_enable(st->vddio_supply);
if (result) {
dev_err(regmap_get_device(st->map),
"Failed to enable regulator: %d\n", result);
} else {
/* Give the device a little bit of time to start up. */
usleep_range(35000, 70000);
}
return result;
}
static int inv_mpu_core_disable_regulator(struct inv_mpu6050_state *st)
{
int result;
result = regulator_disable(st->vddio_supply);
if (result)
dev_err(regmap_get_device(st->map),
"Failed to disable regulator: %d\n", result);
return result;
}
static void inv_mpu_core_disable_regulator_action(void *_data)
{
inv_mpu_core_disable_regulator(_data);
}
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
{
......@@ -992,6 +1026,28 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return -EINVAL;
}
st->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(st->vddio_supply)) {
if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vddio regulator %d\n",
(int)PTR_ERR(st->vddio_supply));
return PTR_ERR(st->vddio_supply);
}
result = inv_mpu_core_enable_regulator(st);
if (result)
return result;
result = devm_add_action(dev, inv_mpu_core_disable_regulator_action,
st);
if (result) {
inv_mpu_core_disable_regulator_action(st);
dev_err(dev, "Failed to setup regulator cleanup action %d\n",
result);
return result;
}
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st);
if (result)
......@@ -1051,7 +1107,12 @@ static int inv_mpu_resume(struct device *dev)
int result;
mutex_lock(&st->lock);
result = inv_mpu_core_enable_regulator(st);
if (result)
goto out_unlock;
result = inv_mpu6050_set_power_itg(st, true);
out_unlock:
mutex_unlock(&st->lock);
return result;
......@@ -1064,6 +1125,7 @@ static int inv_mpu_suspend(struct device *dev)
mutex_lock(&st->lock);
result = inv_mpu6050_set_power_itg(st, false);
inv_mpu_core_disable_regulator(st);
mutex_unlock(&st->lock);
return result;
......
......@@ -129,6 +129,7 @@ struct inv_mpu6050_hw {
* @chip_period: chip internal period estimation (~1kHz).
* @it_timestamp: timestamp from previous interrupt.
* @data_timestamp: timestamp for next data sample.
* @vddio_supply voltage regulator for the chip.
*/
struct inv_mpu6050_state {
struct mutex lock;
......@@ -149,6 +150,7 @@ struct inv_mpu6050_state {
s64 chip_period;
s64 it_timestamp;
s64 data_timestamp;
struct regulator *vddio_supply;
};
/*register and associated bit definition*/
......
......@@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc
ism330dlc, lsm6dso
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
......
......@@ -19,6 +19,7 @@
#define ST_LSM6DSL_DEV_NAME "lsm6dsl"
#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
#define ST_ISM330DLC_DEV_NAME "ism330dlc"
#define ST_LSM6DSO_DEV_NAME "lsm6dso"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
......@@ -26,14 +27,20 @@ enum st_lsm6dsx_hw_id {
ST_LSM6DSL_ID,
ST_LSM6DSM_ID,
ST_ISM330DLC_ID,
ST_LSM6DSO_ID,
ST_LSM6DSX_MAX_ID,
};
#define ST_LSM6DSX_BUFF_SIZE 400
#define ST_LSM6DSX_BUFF_SIZE 512
#define ST_LSM6DSX_CHAN_SIZE 2
#define ST_LSM6DSX_SAMPLE_SIZE 6
#define ST_LSM6DSX_TAG_SIZE 1
#define ST_LSM6DSX_TAGGED_SAMPLE_SIZE (ST_LSM6DSX_SAMPLE_SIZE + \
ST_LSM6DSX_TAG_SIZE)
#define ST_LSM6DSX_MAX_WORD_LEN ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \
ST_LSM6DSX_SAMPLE_SIZE)
#define ST_LSM6DSX_MAX_TAGGED_WORD_LEN ((32 / ST_LSM6DSX_TAGGED_SAMPLE_SIZE) \
* ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
#define ST_LSM6DSX_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask))
struct st_lsm6dsx_reg {
......@@ -41,13 +48,17 @@ struct st_lsm6dsx_reg {
u8 mask;
};
struct st_lsm6dsx_hw;
/**
* struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
* @read_fifo: Read FIFO callback.
* @fifo_th: FIFO threshold register info (addr + mask).
* @fifo_diff: FIFO diff status register info (addr + mask).
* @th_wl: FIFO threshold word length.
*/
struct st_lsm6dsx_fifo_ops {
int (*read_fifo)(struct st_lsm6dsx_hw *hw);
struct {
u8 addr;
u16 mask;
......@@ -79,6 +90,7 @@ struct st_lsm6dsx_hw_ts_settings {
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id supported by the driver configuration.
* @decimator: List of decimator register info (addr + mask).
* @batch: List of FIFO batching register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
* @ts_settings: Hw timer related settings.
*/
......@@ -87,6 +99,7 @@ struct st_lsm6dsx_settings {
u16 max_fifo_size;
enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
struct st_lsm6dsx_hw_ts_settings ts_settings;
};
......@@ -175,5 +188,8 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode);
int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val);
#endif /* ST_LSM6DSX_H */
......@@ -12,6 +12,11 @@
* buffer contains the data of all the enabled FIFO data sets
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
* value of the decimation factor and ODR set for each FIFO data set.
*
* LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Each sample is queued with a tag (1B) indicating data source
* (gyroscope, accelerometer, hw timer).
*
* FIFO supported modes:
* - BYPASS: FIFO disabled
* - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
......@@ -46,6 +51,7 @@
#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
#define ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR 0x78
#define ST_LSM6DSX_REG_TS_RESET_ADDR 0x42
#define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
......@@ -58,6 +64,12 @@ struct st_lsm6dsx_decimator_entry {
u8 val;
};
enum st_lsm6dsx_fifo_tag {
ST_LSM6DSX_GYRO_TAG = 0x01,
ST_LSM6DSX_ACC_TAG = 0x02,
ST_LSM6DSX_TS_TAG = 0x04,
};
static const
struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
{ 0, 0x0 },
......@@ -177,12 +189,34 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
bool enable)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
const struct st_lsm6dsx_reg *batch_reg;
u8 data;
data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
return regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_ODR_MASK,
FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK, data));
batch_reg = &hw->settings->batch[sensor->id];
if (batch_reg->addr) {
int val;
if (enable) {
int err;
err = st_lsm6dsx_check_odr(sensor, sensor->odr,
&data);
if (err < 0)
return err;
} else {
data = 0;
}
val = ST_LSM6DSX_SHIFT_VAL(data, batch_reg->mask);
return regmap_update_bits(hw->regmap, batch_reg->addr,
batch_reg->mask, val);
} else {
data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
return regmap_update_bits(hw->regmap,
ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_ODR_MASK,
FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
data));
}
}
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
......@@ -251,21 +285,21 @@ static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
}
/*
* Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN in order to avoid
* a kmalloc for each bus access
* Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN/ST_LSM6DSX_MAX_TAGGED_WORD_LEN
* in order to avoid a kmalloc for each bus access
*/
static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
unsigned int data_len)
static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
u8 *data, unsigned int data_len,
unsigned int max_word_len)
{
unsigned int word_len, read_len = 0;
int err;
while (read_len < data_len) {
word_len = min_t(unsigned int, data_len - read_len,
ST_LSM6DSX_MAX_WORD_LEN);
err = regmap_bulk_read(hw->regmap,
ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
data + read_len, word_len);
max_word_len);
err = regmap_bulk_read(hw->regmap, addr, data + read_len,
word_len);
if (err < 0)
return err;
read_len += word_len;
......@@ -283,7 +317,7 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
*
* Return: Number of bytes read from the FIFO
*/
static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
{
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
......@@ -315,7 +349,9 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
hw->buff, pattern_len,
ST_LSM6DSX_MAX_WORD_LEN);
if (err < 0) {
dev_err(hw->dev,
"failed to read pattern from fifo (err=%d)\n",
......@@ -401,13 +437,111 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
return read_len;
}
/**
* st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
*
* Read samples from the hw FIFO and push them to IIO buffers.
*
* Return: Number of bytes read from the FIFO
*/
int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
{
u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
u16 fifo_len, fifo_diff_mask;
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag;
bool reset_ts = false;
int i, err, read_len;
__le16 fifo_status;
s64 ts = 0;
err = regmap_bulk_read(hw->regmap,
hw->settings->fifo_ops.fifo_diff.addr,
&fifo_status, sizeof(fifo_status));
if (err < 0) {
dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
err);
return err;
}
fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
if (!fifo_len)
return 0;
acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
err = st_lsm6dsx_read_block(hw,
ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR,
hw->buff, pattern_len,
ST_LSM6DSX_MAX_TAGGED_WORD_LEN);
if (err < 0) {
dev_err(hw->dev,
"failed to read pattern from fifo (err=%d)\n",
err);
return err;
}
for (i = 0; i < pattern_len;
i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) {
memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE],
ST_LSM6DSX_SAMPLE_SIZE);
tag = hw->buff[i] >> 3;
switch (tag) {
case ST_LSM6DSX_TS_TAG:
/*
* hw timestamp is 4B long and it is stored
* in FIFO according to this schema:
* B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16],
* B3 = ts[31:24]
*/
ts = le32_to_cpu(*((__le32 *)iio_buff));
/*
* check if hw timestamp engine is going to
* reset (the sensor generates an interrupt
* to signal the hw timestamp will reset in
* 1.638s)
*/
if (!reset_ts && ts >= 0xffff0000)
reset_ts = true;
ts *= ST_LSM6DSX_TS_SENSITIVITY;
break;
case ST_LSM6DSX_GYRO_TAG:
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_GYRO],
iio_buff, gyro_sensor->ts_ref + ts);
break;
case ST_LSM6DSX_ACC_TAG:
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_ACC],
iio_buff, acc_sensor->ts_ref + ts);
break;
default:
break;
}
}
}
if (unlikely(reset_ts)) {
err = st_lsm6dsx_reset_hw_ts(hw);
if (err < 0)
return err;
}
return read_len;
}
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
{
int err;
mutex_lock(&hw->fifo_lock);
st_lsm6dsx_read_fifo(hw);
hw->settings->fifo_ops.read_fifo(hw);
err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
mutex_unlock(&hw->fifo_lock);
......@@ -479,7 +613,7 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
int count;
mutex_lock(&hw->fifo_lock);
count = st_lsm6dsx_read_fifo(hw);
count = hw->settings->fifo_ops.read_fifo(hw);
mutex_unlock(&hw->fifo_lock);
return !count ? IRQ_NONE : IRQ_HANDLED;
......
......@@ -23,6 +23,12 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB
*
* - LSM6DSO
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 3KB
*
* Copyright 2016 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
......@@ -171,6 +177,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
......@@ -217,6 +224,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
......@@ -265,6 +273,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
.fifo_ops = {
.read_fifo = st_lsm6dsx_read_fifo,
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(10, 0),
......@@ -294,6 +303,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
},
},
{
.wai = 0x6c,
.max_fifo_size = 512,
.id = {
[0] = ST_LSM6DSO_ID,
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x09,
.mask = GENMASK(3, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x09,
.mask = GENMASK(7, 4),
},
},
.fifo_ops = {
.read_fifo = st_lsm6dsx_read_tagged_fifo,
.fifo_th = {
.addr = 0x07,
.mask = GENMASK(8, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(8, 0),
},
.th_wl = 1,
},
.ts_settings = {
.timer_en = {
.addr = 0x19,
.mask = BIT(5),
},
.decimator = {
.addr = 0x0a,
.mask = GENMASK(7, 6),
},
},
},
};
#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \
......@@ -395,8 +443,7 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
return 0;
}
static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr,
u8 *val)
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
{
int i;
......
......@@ -61,6 +61,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,ism330dlc",
.data = (void *)ST_ISM330DLC_ID,
},
{
.compatible = "st,lsm6dso",
.data = (void *)ST_LSM6DSO_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
......@@ -71,6 +75,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
{ ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
......
......@@ -61,6 +61,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,ism330dlc",
.data = (void *)ST_ISM330DLC_ID,
},
{
.compatible = "st,lsm6dso",
.data = (void *)ST_LSM6DSO_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
......@@ -71,6 +75,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{ ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
{ ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
......
// SPDX-License-Identifier: GPL-2.0
/*
* ROHM BH1710/BH1715/BH1721/BH1750/BH1751 ambient light sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Data sheets:
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1710fvc-e.pdf
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1715fvc-e.pdf
......@@ -281,8 +278,7 @@ static int bh1750_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int bh1750_suspend(struct device *dev)
static int __maybe_unused bh1750_suspend(struct device *dev)
{
int ret;
struct bh1750_data *data =
......@@ -300,10 +296,6 @@ static int bh1750_suspend(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
#define BH1750_PM_OPS (&bh1750_pm_ops)
#else
#define BH1750_PM_OPS NULL
#endif
static const struct i2c_device_id bh1750_id[] = {
{ "bh1710", BH1710 },
......@@ -318,7 +310,7 @@ MODULE_DEVICE_TABLE(i2c, bh1750_id);
static struct i2c_driver bh1750_driver = {
.driver = {
.name = "bh1750",
.pm = BH1750_PM_OPS,
.pm = &bh1750_pm_ops,
},
.probe = bh1750_probe,
.remove = bh1750_remove,
......
......@@ -99,7 +99,6 @@ static const int max44000_alspga_shift[] = {0, 2, 4, 7};
* Handling this internally is also required for buffer support because the
* channel's scan_type can't be modified dynamically.
*/
static const int max44000_alstim_shift[] = {0, 2, 4, 6};
#define MAX44000_ALSTIM_SHIFT(alstim) (2 * (alstim))
/* Available integration times with pretty manual alignment: */
......
......@@ -20,6 +20,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/platform_data/tsl2772.h>
#include <linux/regulator/consumer.h>
/* Cal defs */
#define PROX_STAT_CAL 0
......@@ -107,6 +108,11 @@
#define TSL2772_ALS_GAIN_TRIM_MIN 250
#define TSL2772_ALS_GAIN_TRIM_MAX 4000
#define TSL2772_MAX_PROX_LEDS 2
#define TSL2772_BOOT_MIN_SLEEP_TIME 10000
#define TSL2772_BOOT_MAX_SLEEP_TIME 28000
/* Device family members */
enum {
tsl2571,
......@@ -118,7 +124,8 @@ enum {
tsl2672,
tmd2672,
tsl2772,
tmd2772
tmd2772,
apds9930,
};
enum {
......@@ -141,11 +148,21 @@ struct tsl2772_chip_info {
const struct iio_info *info;
};
static const int tsl2772_led_currents[][2] = {
{ 100000, TSL2772_100_mA },
{ 50000, TSL2772_50_mA },
{ 25000, TSL2772_25_mA },
{ 13000, TSL2772_13_mA },
{ 0, 0 }
};
struct tsl2772_chip {
kernel_ulong_t id;
struct mutex prox_mutex;
struct mutex als_mutex;
struct i2c_client *client;
struct regulator *vdd_supply;
struct regulator *vddio_supply;
u16 prox_data;
struct tsl2772_als_info als_cur_info;
struct tsl2772_settings settings;
......@@ -197,6 +214,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
{ 0, 0 },
};
static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
{ 52000, 96824 },
{ 38792, 67132 },
{ 0, 0 },
};
static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
[tsl2571] = tsl2x71_lux_table,
[tsl2671] = tsl2x71_lux_table,
......@@ -208,6 +231,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
[tmd2672] = tmd2x72_lux_table,
[tsl2772] = tsl2x72_lux_table,
[tmd2772] = tmd2x72_lux_table,
[apds9930] = apds9930_lux_table,
};
static const struct tsl2772_settings tsl2772_default_settings = {
......@@ -258,6 +282,7 @@ static const int tsl2772_int_time_avail[][6] = {
[tmd2672] = { 0, 2730, 0, 2730, 0, 699000 },
[tsl2772] = { 0, 2730, 0, 2730, 0, 699000 },
[tmd2772] = { 0, 2730, 0, 2730, 0, 699000 },
[apds9930] = { 0, 2730, 0, 2730, 0, 699000 },
};
static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 };
......@@ -283,7 +308,8 @@ static const u8 device_channel_config[] = {
[tsl2672] = PRX2,
[tmd2672] = PRX2,
[tsl2772] = ALSPRX2,
[tmd2772] = ALSPRX2
[tmd2772] = ALSPRX2,
[apds9930] = ALSPRX2,
};
static int tsl2772_read_status(struct tsl2772_chip *chip)
......@@ -497,6 +523,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev)
case tmd2672:
case tsl2772:
case tmd2772:
case apds9930:
if (!(ret & TSL2772_STA_PRX_VALID)) {
ret = -EINVAL;
goto prox_poll_err;
......@@ -515,6 +542,75 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev)
return ret;
}
static int tsl2772_read_prox_led_current(struct tsl2772_chip *chip)
{
struct device_node *of_node = chip->client->dev.of_node;
int ret, tmp, i;
ret = of_property_read_u32(of_node, "led-max-microamp", &tmp);
if (ret < 0)
return ret;
for (i = 0; tsl2772_led_currents[i][0] != 0; i++) {
if (tmp == tsl2772_led_currents[i][0]) {
chip->settings.prox_power = tsl2772_led_currents[i][1];
return 0;
}
}
dev_err(&chip->client->dev, "Invalid value %d for led-max-microamp\n",
tmp);
return -EINVAL;
}
static int tsl2772_read_prox_diodes(struct tsl2772_chip *chip)
{
struct device_node *of_node = chip->client->dev.of_node;
int i, ret, num_leds, prox_diode_mask;
u32 leds[TSL2772_MAX_PROX_LEDS];
ret = of_property_count_u32_elems(of_node, "amstaos,proximity-diodes");
if (ret < 0)
return ret;
num_leds = ret;
if (num_leds > TSL2772_MAX_PROX_LEDS)
num_leds = TSL2772_MAX_PROX_LEDS;
ret = of_property_read_u32_array(of_node, "amstaos,proximity-diodes",
leds, num_leds);
if (ret < 0) {
dev_err(&chip->client->dev,
"Invalid value for amstaos,proximity-diodes: %d.\n",
ret);
return ret;
}
prox_diode_mask = 0;
for (i = 0; i < num_leds; i++) {
if (leds[i] == 0)
prox_diode_mask |= TSL2772_DIODE0;
else if (leds[i] == 1)
prox_diode_mask |= TSL2772_DIODE1;
else {
dev_err(&chip->client->dev,
"Invalid value %d in amstaos,proximity-diodes.\n",
leds[i]);
return -EINVAL;
}
}
return 0;
}
static void tsl2772_parse_dt(struct tsl2772_chip *chip)
{
tsl2772_read_prox_led_current(chip);
tsl2772_read_prox_diodes(chip);
}
/**
* tsl2772_defaults() - Populates the device nominal operating parameters
* with those provided by a 'platform' data struct or
......@@ -541,6 +637,8 @@ static void tsl2772_defaults(struct tsl2772_chip *chip)
memcpy(chip->tsl2772_device_lux,
tsl2772_default_lux_table_group[chip->id],
TSL2772_DEFAULT_TABLE_BYTES);
tsl2772_parse_dt(chip);
}
/**
......@@ -595,6 +693,52 @@ static int tsl2772_als_calibrate(struct iio_dev *indio_dev)
return ret;
}
static void tsl2772_disable_regulators_action(void *_data)
{
struct tsl2772_chip *chip = _data;
regulator_disable(chip->vdd_supply);
regulator_disable(chip->vddio_supply);
}
static int tsl2772_enable_regulator(struct tsl2772_chip *chip,
struct regulator *regulator)
{
int ret;
ret = regulator_enable(regulator);
if (ret < 0) {
dev_err(&chip->client->dev, "Failed to enable regulator: %d\n",
ret);
return ret;
}
return 0;
}
static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip,
char *name)
{
struct regulator *regulator;
int ret;
regulator = devm_regulator_get(&chip->client->dev, name);
if (IS_ERR(regulator)) {
if (PTR_ERR(regulator) != -EPROBE_DEFER)
dev_err(&chip->client->dev,
"Failed to get %s regulator %d\n",
name, (int)PTR_ERR(regulator));
return regulator;
}
ret = tsl2772_enable_regulator(chip, regulator);
if (ret < 0)
return ERR_PTR(ret);
return regulator;
}
static int tsl2772_chip_on(struct iio_dev *indio_dev)
{
struct tsl2772_chip *chip = iio_priv(indio_dev);
......@@ -1260,6 +1404,7 @@ static int tsl2772_device_id_verif(int id, int target)
case tmd2672:
case tsl2772:
case tmd2772:
case apds9930:
return (id & 0xf0) == SWORDFISH_ID;
}
......@@ -1652,6 +1797,27 @@ static int tsl2772_probe(struct i2c_client *clientp,
chip->client = clientp;
i2c_set_clientdata(clientp, indio_dev);
chip->vddio_supply = tsl2772_get_regulator(chip, "vddio");
if (IS_ERR(chip->vddio_supply))
return PTR_ERR(chip->vddio_supply);
chip->vdd_supply = tsl2772_get_regulator(chip, "vdd");
if (IS_ERR(chip->vdd_supply)) {
regulator_disable(chip->vddio_supply);
return PTR_ERR(chip->vdd_supply);
}
ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action,
chip);
if (ret < 0) {
tsl2772_disable_regulators_action(chip);
dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n",
ret);
return ret;
}
usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
ret = i2c_smbus_read_byte_data(chip->client,
TSL2772_CMD_REG | TSL2772_CHIPID);
if (ret < 0)
......@@ -1725,13 +1891,33 @@ static int tsl2772_probe(struct i2c_client *clientp,
static int tsl2772_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2772_chip *chip = iio_priv(indio_dev);
int ret;
ret = tsl2772_chip_off(indio_dev);
regulator_disable(chip->vdd_supply);
regulator_disable(chip->vddio_supply);
return tsl2772_chip_off(indio_dev);
return ret;
}
static int tsl2772_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tsl2772_chip *chip = iio_priv(indio_dev);
int ret;
ret = tsl2772_enable_regulator(chip, chip->vddio_supply);
if (ret < 0)
return ret;
ret = tsl2772_enable_regulator(chip, chip->vdd_supply);
if (ret < 0) {
regulator_disable(chip->vddio_supply);
return ret;
}
usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
return tsl2772_chip_on(indio_dev);
}
......@@ -1758,6 +1944,7 @@ static const struct i2c_device_id tsl2772_idtable[] = {
{ "tmd2672", tmd2672 },
{ "tsl2772", tsl2772 },
{ "tmd2772", tmd2772 },
{ "apds9930", apds9930},
{}
};
......@@ -1774,6 +1961,7 @@ static const struct of_device_id tsl2772_of_match[] = {
{ .compatible = "amstaos,tmd2672" },
{ .compatible = "amstaos,tsl2772" },
{ .compatible = "amstaos,tmd2772" },
{ .compatible = "avago,apds9930" },
{}
};
MODULE_DEVICE_TABLE(of, tsl2772_of_match);
......
// SPDX-License-Identifier: GPL-2.0
/*
* IIO multiplexer driver
*
* Copyright (C) 2017 Axentia Technologies AB
*
* Author: Peter Rosin <peda@axentia.se>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/err.h>
......
......@@ -137,7 +137,6 @@ static int max5481_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct max5481_data *data;
const struct spi_device_id *id = spi_get_device_id(spi);
const struct of_device_id *match;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
......@@ -149,10 +148,8 @@ static int max5481_probe(struct spi_device *spi)
data->spi = spi;
match = of_match_device(of_match_ptr(max5481_match), &spi->dev);
if (match)
data->cfg = of_device_get_match_data(&spi->dev);
else
data->cfg = of_device_get_match_data(&spi->dev);
if (!data->cfg)
data->cfg = &max5481_cfg[id->driver_data];
indio_dev->name = id->name;
......
......@@ -147,7 +147,6 @@ static int mcp4018_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct mcp4018_data *data;
struct iio_dev *indio_dev;
const struct of_device_id *match;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE)) {
......@@ -162,10 +161,8 @@ static int mcp4018_probe(struct i2c_client *client)
i2c_set_clientdata(client, indio_dev);
data->client = client;
match = of_match_device(of_match_ptr(mcp4018_of_match), dev);
if (match)
data->cfg = of_device_get_match_data(dev);
else
data->cfg = of_device_get_match_data(dev);
if (!data->cfg)
data->cfg = &mcp4018_cfg[i2c_match_id(mcp4018_id, client)->driver_data];
indio_dev->dev.parent = dev;
......@@ -190,4 +187,4 @@ module_i2c_driver(mcp4018_driver);
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("MCP4018 digital potentiometer");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* Industrial I/O driver for Microchip digital potentiometers
* Copyright (c) 2015 Axentia Technologies AB
......@@ -22,10 +23,6 @@
* mcp4652 2 257 5, 10, 50, 100 01011xx
* mcp4661 2 257 5, 10, 50, 100 0101xxx
* mcp4662 2 257 5, 10, 50, 100 01011xx
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/module.h>
......@@ -360,7 +357,6 @@ static int mcp4531_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct mcp4531_data *data;
struct iio_dev *indio_dev;
const struct of_device_id *match;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
......@@ -375,10 +371,8 @@ static int mcp4531_probe(struct i2c_client *client)
i2c_set_clientdata(client, indio_dev);
data->client = client;
match = of_match_device(of_match_ptr(mcp4531_of_match), dev);
if (match)
data->cfg = of_device_get_match_data(dev);
else
data->cfg = of_device_get_match_data(dev);
if (!data->cfg)
data->cfg = &mcp4531_cfg[i2c_match_id(mcp4531_id, client)->driver_data];
indio_dev->dev.parent = dev;
......@@ -403,4 +397,4 @@ module_i2c_driver(mcp4531_driver);
MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
MODULE_DESCRIPTION("MCP4531 digital potentiometer");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* MS5611 pressure and temperature sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _MS5611_H
......
// SPDX-License-Identifier: GPL-2.0
/*
* MS5611 pressure and temperature sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Data sheet:
* http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
* http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
......
// SPDX-License-Identifier: GPL-2.0
/*
* MS5611 pressure and temperature sensor driver (I2C bus)
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 7-bit I2C slave addresses:
*
* 0x77 (CSB pin low)
......@@ -117,9 +114,7 @@ static int ms5611_i2c_remove(struct i2c_client *client)
#if defined(CONFIG_OF)
static const struct of_device_id ms5611_i2c_matches[] = {
{ .compatible = "meas,ms5611" },
{ .compatible = "ms5611" },
{ .compatible = "meas,ms5607" },
{ .compatible = "ms5607" },
{ }
};
MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
......
// SPDX-License-Identifier: GPL-2.0
/*
* MS5611 pressure and temperature sensor driver (SPI bus)
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/delay.h>
......@@ -119,9 +116,7 @@ static int ms5611_spi_remove(struct spi_device *spi)
#if defined(CONFIG_OF)
static const struct of_device_id ms5611_spi_matches[] = {
{ .compatible = "meas,ms5611" },
{ .compatible = "ms5611" },
{ .compatible = "meas,ms5607" },
{ .compatible = "ms5607" },
{ }
};
MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
......
......@@ -232,7 +232,6 @@ static u32 isl29501_register_write(struct isl29501_private *isl29501,
u32 value)
{
const struct isl29501_register_desc *reg = &isl29501_registers[name];
u8 msb, lsb;
int ret;
if (!reg->msb && value > U8_MAX)
......@@ -241,22 +240,15 @@ static u32 isl29501_register_write(struct isl29501_private *isl29501,
if (value > U16_MAX)
return -ERANGE;
if (!reg->msb) {
lsb = value & 0xFF;
} else {
msb = (value >> 8) & 0xFF;
lsb = value & 0xFF;
}
mutex_lock(&isl29501->lock);
if (reg->msb) {
ret = i2c_smbus_write_byte_data(isl29501->client,
reg->msb, msb);
reg->msb, value >> 8);
if (ret < 0)
goto err;
}
ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, lsb);
ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
err:
mutex_unlock(&isl29501->lock);
......
......@@ -222,7 +222,7 @@ static void __exit iio_sysfs_trig_exit(void)
}
module_exit(iio_sysfs_trig_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:iio-trig-sysfs");
......@@ -761,6 +761,6 @@ static struct spi_driver ad7192_driver = {
};
module_spi_driver(ad7192_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
MODULE_LICENSE("GPL v2");
......@@ -987,6 +987,6 @@ static struct spi_driver ad7280_driver = {
};
module_spi_driver(ad7280_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7280A");
MODULE_LICENSE("GPL v2");
......@@ -534,6 +534,6 @@ EXPORT_SYMBOL_GPL(ad7606_pm_ops);
#endif
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
......@@ -105,6 +105,6 @@ static struct platform_driver ad7606_driver = {
module_platform_driver(ad7606_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
......@@ -73,6 +73,6 @@ static struct spi_driver ad7606_driver = {
};
module_spi_driver(ad7606_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");
......@@ -260,6 +260,6 @@ static struct spi_driver ad7780_driver = {
};
module_spi_driver(ad7780_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs");
MODULE_LICENSE("GPL v2");
......@@ -758,6 +758,6 @@ static struct i2c_driver ad7746_driver = {
};
module_i2c_driver(ad7746_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7746/5/7 capacitive sensor driver");
MODULE_LICENSE("GPL v2");
......@@ -454,6 +454,6 @@ static struct spi_driver ad9832_driver = {
};
module_spi_driver(ad9832_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS");
MODULE_LICENSE("GPL v2");
......@@ -526,6 +526,6 @@ static struct spi_driver ad9834_driver = {
};
module_spi_driver(ad9834_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS");
MODULE_LICENSE("GPL v2");
......@@ -797,6 +797,6 @@ static struct i2c_driver ad5933_driver = {
};
module_i2c_driver(ad5933_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5933 Impedance Conv. Network Analyzer");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* Copyright (c) 2012-2014,2018 The Linux Foundation. All rights reserved.
*/
#ifndef _DT_BINDINGS_QCOM_SPMI_VADC_H
......@@ -116,4 +108,117 @@
#define VADC_LR_MUX10_PU1_PU2_AMUX_USB_ID 0xf9
#define VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM 0xfc
/* ADC channels for SPMI PMIC5 */
#define ADC5_REF_GND 0x00
#define ADC5_1P25VREF 0x01
#define ADC5_VREF_VADC 0x02
#define ADC5_VREF_VADC5_DIV_3 0x82
#define ADC5_VPH_PWR 0x83
#define ADC5_VBAT_SNS 0x84
#define ADC5_VCOIN 0x85
#define ADC5_DIE_TEMP 0x06
#define ADC5_USB_IN_I 0x07
#define ADC5_USB_IN_V_16 0x08
#define ADC5_CHG_TEMP 0x09
#define ADC5_BAT_THERM 0x0a
#define ADC5_BAT_ID 0x0b
#define ADC5_XO_THERM 0x0c
#define ADC5_AMUX_THM1 0x0d
#define ADC5_AMUX_THM2 0x0e
#define ADC5_AMUX_THM3 0x0f
#define ADC5_AMUX_THM4 0x10
#define ADC5_AMUX_THM5 0x11
#define ADC5_GPIO1 0x12
#define ADC5_GPIO2 0x13
#define ADC5_GPIO3 0x14
#define ADC5_GPIO4 0x15
#define ADC5_GPIO5 0x16
#define ADC5_GPIO6 0x17
#define ADC5_GPIO7 0x18
#define ADC5_SBUx 0x99
#define ADC5_MID_CHG_DIV6 0x1e
#define ADC5_OFF 0xff
/* 30k pull-up1 */
#define ADC5_BAT_THERM_30K_PU 0x2a
#define ADC5_BAT_ID_30K_PU 0x2b
#define ADC5_XO_THERM_30K_PU 0x2c
#define ADC5_AMUX_THM1_30K_PU 0x2d
#define ADC5_AMUX_THM2_30K_PU 0x2e
#define ADC5_AMUX_THM3_30K_PU 0x2f
#define ADC5_AMUX_THM4_30K_PU 0x30
#define ADC5_AMUX_THM5_30K_PU 0x31
#define ADC5_GPIO1_30K_PU 0x32
#define ADC5_GPIO2_30K_PU 0x33
#define ADC5_GPIO3_30K_PU 0x34
#define ADC5_GPIO4_30K_PU 0x35
#define ADC5_GPIO5_30K_PU 0x36
#define ADC5_GPIO6_30K_PU 0x37
#define ADC5_GPIO7_30K_PU 0x38
#define ADC5_SBUx_30K_PU 0x39
/* 100k pull-up2 */
#define ADC5_BAT_THERM_100K_PU 0x4a
#define ADC5_BAT_ID_100K_PU 0x4b
#define ADC5_XO_THERM_100K_PU 0x4c
#define ADC5_AMUX_THM1_100K_PU 0x4d
#define ADC5_AMUX_THM2_100K_PU 0x4e
#define ADC5_AMUX_THM3_100K_PU 0x4f
#define ADC5_AMUX_THM4_100K_PU 0x50
#define ADC5_AMUX_THM5_100K_PU 0x51
#define ADC5_GPIO1_100K_PU 0x52
#define ADC5_GPIO2_100K_PU 0x53
#define ADC5_GPIO3_100K_PU 0x54
#define ADC5_GPIO4_100K_PU 0x55
#define ADC5_GPIO5_100K_PU 0x56
#define ADC5_GPIO6_100K_PU 0x57
#define ADC5_GPIO7_100K_PU 0x58
#define ADC5_SBUx_100K_PU 0x59
/* 400k pull-up3 */
#define ADC5_BAT_THERM_400K_PU 0x6a
#define ADC5_BAT_ID_400K_PU 0x6b
#define ADC5_XO_THERM_400K_PU 0x6c
#define ADC5_AMUX_THM1_400K_PU 0x6d
#define ADC5_AMUX_THM2_400K_PU 0x6e
#define ADC5_AMUX_THM3_400K_PU 0x6f
#define ADC5_AMUX_THM4_400K_PU 0x70
#define ADC5_AMUX_THM5_400K_PU 0x71
#define ADC5_GPIO1_400K_PU 0x72
#define ADC5_GPIO2_400K_PU 0x73
#define ADC5_GPIO3_400K_PU 0x74
#define ADC5_GPIO4_400K_PU 0x75
#define ADC5_GPIO5_400K_PU 0x76
#define ADC5_GPIO6_400K_PU 0x77
#define ADC5_GPIO7_400K_PU 0x78
#define ADC5_SBUx_400K_PU 0x79
/* 1/3 Divider */
#define ADC5_GPIO1_DIV3 0x92
#define ADC5_GPIO2_DIV3 0x93
#define ADC5_GPIO3_DIV3 0x94
#define ADC5_GPIO4_DIV3 0x95
#define ADC5_GPIO5_DIV3 0x96
#define ADC5_GPIO6_DIV3 0x97
#define ADC5_GPIO7_DIV3 0x98
#define ADC5_SBUx_DIV3 0x99
/* Current and combined current/voltage channels */
#define ADC5_INT_EXT_ISENSE 0xa1
#define ADC5_PARALLEL_ISENSE 0xa5
#define ADC5_CUR_REPLICA_VDS 0xa7
#define ADC5_CUR_SENS_BATFET_VDS_OFFSET 0xa9
#define ADC5_CUR_SENS_REPLICA_VDS_OFFSET 0xab
#define ADC5_EXT_SENS_OFFSET 0xad
#define ADC5_INT_EXT_ISENSE_VBAT_VDATA 0xb0
#define ADC5_INT_EXT_ISENSE_VBAT_IDATA 0xb1
#define ADC5_EXT_ISENSE_VBAT_VDATA 0xb2
#define ADC5_EXT_ISENSE_VBAT_IDATA 0xb3
#define ADC5_PARALLEL_ISENSE_VBAT_VDATA 0xb4
#define ADC5_PARALLEL_ISENSE_VBAT_IDATA 0xb5
#define ADC5_MAX_CHANNEL 0xc0
#endif /* _DT_BINDINGS_QCOM_SPMI_VADC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment