Commit e266ca36 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'staging-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging/IIO updates from Greg KH:
 "Here is the big staging/iio driver pull request for 5.1-rc1.

  Lots of good IIO driver updates and cleanups in here as always.
  Combined with the removal of the xgifb driver, we have a net "loss" of
  over 9000 lines in the pull request, always a nice thing.

  As the outreachy application process is currently happening, there are
  loads of tiny checkpatch cleanup fixes all over the staging tree,
  which accounts for the majority of the fixups"

* tag 'staging-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (341 commits)
  staging: mt7621-dma: remove license boilerplate text
  staging: mt7621-dma: add SPDX GPL-2.0+ license identifier
  Staging: ks7010: Replace typecast to int
  Staging: vt6655: Align a static function declaration
  staging: speakup: fix line over 80 characters.
  staging: mt7621-eth: Remove license boilerplate text
  staging: mt7621-eth: Add SPDX license identifier
  staging: ks7010: removed custom Michael MIC implementation.
  staging: rtl8192e: Fix space and suspect issue
  Staging: vt6655: Modify comment style of SPDX License Identifier
  Staging: vt6655: Modify comment style for SPDX-License-Identifier
  Staging: vt6655: Align a function declaration
  Staging: vt6655: Alignment of function declaration
  staging: rtl8712: Fix indentation issue
  staging: wilc1000: fix incorrent type in initializer
  staging: rtl8188eu: remove unused P2P_PRIVATE_IOCTL_SET_LEN
  staging: rtl8188eu: remove unused enum P2P_PROTO_WK_ID
  staging: rtl8723bs: Remove duplicated include from drv_types.h
  Staging: vt6655: Alignment should match open parenthesis
  staging: erofs: fix mis-acted TAIL merging behavior
  ...
parents e0f0ae83 1f08c4a5
......@@ -1554,6 +1554,10 @@ What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_ethanol_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_ethanol_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_h2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_h2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
KernelVersion: 4.3
......@@ -1684,4 +1688,19 @@ KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled) phase difference reading from channel Y
that can be processed to radians.
\ No newline at end of file
that can be processed to radians.
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm1_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm1_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm2p5_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm2p5_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm4_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm4_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentration_pm10_input
What: /sys/bus/iio/devices/iio:deviceX/in_massconcentrationY_pm10_input
KernelVersion: 4.22
Contact: linux-iio@vger.kernel.org
Description:
Mass concentration reading of particulate matter in ug / m3.
pmX consists of particles with aerodynamic diameter less or
equal to X micrometers.
What: /sys/bus/iio/devices/iio:deviceX/start_cleaning
Date: December 2018
KernelVersion: 4.22
Contact: linux-iio@vger.kernel.org
Description:
Writing 1 starts sensor self cleaning. Internal fan accelerates
to its maximum speed and keeps spinning for about 10 seconds in
order to blow out accumulated dust.
What: /sys/bus/iio/devices/iio:deviceX/cleaning_period
Date: January 2019
KernelVersion: 5.1
Contact: linux-iio@vger.kernel.org
Description:
Sensor is capable of triggering self cleaning periodically.
Period can be changed by writing a new value here. Upon reading
the current one is returned. Units are seconds.
Writing 0 disables periodical self cleaning entirely.
What: /sys/bus/iio/devices/iio:deviceX/cleaning_period_available
Date: January 2019
KernelVersion: 5.1
Contact: linux-iio@vger.kernel.org
Description:
The range of available values in seconds represented as the
minimum value, the step and the maximum value, all enclosed in
square brackets.
......@@ -20,6 +20,10 @@ Optional properties:
- interrupt-names: should contain "INT1" and/or "INT2", the accelerometer's
interrupt line in use.
- vdd-supply: phandle to the regulator that provides vdd power to the accelerometer.
- vddio-supply: phandle to the regulator that provides vddio power to the accelerometer.
Example:
mma8453fc@1d {
......
Analog Devices AD7606 Simultaneous Sampling ADC
Required properties for the AD7606:
- compatible: Must be one of
* "adi,ad7605-4"
* "adi,ad7606-8"
* "adi,ad7606-6"
* "adi,ad7606-4"
- reg: SPI chip select number for the device
- spi-max-frequency: Max SPI frequency to use
see: Documentation/devicetree/bindings/spi/spi-bus.txt
- spi-cpha: See Documentation/devicetree/bindings/spi/spi-bus.txt
- avcc-supply: phandle to the Avcc power supply
- interrupts: IRQ line for the ADC
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- adi,conversion-start-gpios: must be the device tree identifier of the CONVST pin.
This logic input is used to initiate conversions on the analog
input channels. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
Optional properties:
- reset-gpios: must be the device tree identifier of the RESET pin. If specified,
it will be asserted during driver probe. As the line is active high,
it should be marked GPIO_ACTIVE_HIGH.
- standby-gpios: must be the device tree identifier of the STBY pin. This pin is used
to place the AD7606 into one of two power-down modes, Standby mode or
Shutdown mode. As the line is active low, it should be marked
GPIO_ACTIVE_LOW.
- adi,first-data-gpios: must be the device tree identifier of the FRSTDATA pin.
The FRSTDATA output indicates when the first channel, V1, is
being read back on either the parallel, byte or serial interface.
As the line is active high, it should be marked GPIO_ACTIVE_HIGH.
- adi,range-gpios: must be the device tree identifier of the RANGE pin. The polarity on
this pin determines the input range of the analog input channels. If
this pin is tied to a logic high, the analog input range is ±10V for
all channels. If this pin is tied to a logic low, the analog input range
is ±5V for all channels. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
- adi,oversampling-ratio-gpios: must be the device tree identifier of the over-sampling
mode pins. As the line is active high, it should be marked
GPIO_ACTIVE_HIGH.
Example:
adc@0 {
compatible = "adi,ad7606-8";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
avcc-supply = <&adc_vref>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
adi,conversion-start-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
adi,first-data-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
adi,oversampling-ratio-gpios = <&gpio 18 GPIO_ACTIVE_HIGH
&gpio 23 GPIO_ACTIVE_HIGH
&gpio 26 GPIO_ACTIVE_HIGH>;
standby-gpios = <&gpio 24 GPIO_ACTIVE_LOW>;
};
Analog Devices AD7768-1 ADC device driver
Required properties for the AD7768-1:
- compatible: Must be "adi,ad7768-1"
- reg: SPI chip select number for the device
- spi-max-frequency: Max SPI frequency to use
see: Documentation/devicetree/bindings/spi/spi-bus.txt
- clocks: phandle to the master clock (mclk)
see: Documentation/devicetree/bindings/clock/clock-bindings.txt
- clock-names: Must be "mclk".
- interrupts: IRQ line for the ADC
see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- vref-supply: vref supply can be used as reference for conversion
- adi,sync-in-gpios: must be the device tree identifier of the SYNC-IN pin. Enables
synchronization of multiple devices that require simultaneous sampling.
A pulse is always required if the configuration is changed in any way, for example
if the filter decimation rate changes. As the line is active low, it should
be marked GPIO_ACTIVE_LOW.
Optional properties:
- reset-gpios : GPIO spec for the RESET pin. If specified, it will be asserted during
driver probe. As the line is active low, it should be marked GPIO_ACTIVE_LOW.
Example:
adc@0 {
compatible = "adi,ad7768-1";
reg = <0>;
spi-max-frequency = <2000000>;
spi-cpol;
spi-cpha;
vref-supply = <&adc_vref>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio>;
adi,sync-in-gpios = <&gpio 22 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
clocks = <&ad7768_mclk>;
clock-names = "mclk";
};
......@@ -23,6 +23,10 @@ Required properties:
- #io-channel-cells: must be 1, see ../iio-bindings.txt
Optional properties:
- amlogic,hhi-sysctrl: phandle to the syscon which contains the 5th bit
of the TSC (temperature sensor coefficient) on
Meson8b and Meson8m2 (which used to calibrate the
temperature sensor)
- nvmem-cells: phandle to the temperature_calib eFuse cells
- nvmem-cell-names: if present (to enable the temperature sensor
calibration) this must contain "temperature_calib"
......
* Ingenic JZ47xx ADC controller IIO bindings
Required properties:
- compatible: Should be one of:
* ingenic,jz4725b-adc
* ingenic,jz4740-adc
- reg: ADC controller registers location and length.
- clocks: phandle to the SoC's ADC clock.
- clock-names: Must be set to "adc".
- #io-channel-cells: Must be set to <1> to indicate channels are selected
by index.
ADC clients must use the format described in iio-bindings.txt, giving
a phandle and IIO specifier pair ("io-channels") to the ADC controller.
Example:
#include <dt-bindings/iio/adc/ingenic,adc.h>
adc: adc@10070000 {
compatible = "ingenic,jz4740-adc";
#io-channel-cells = <1>;
reg = <0x10070000 0x30>;
clocks = <&cgu JZ4740_CLK_ADC>;
clock-names = "adc";
interrupt-parent = <&intc>;
interrupts = <18>;
};
adc-keys {
...
compatible = "adc-keys";
io-channels = <&adc INGENIC_ADC_AUX>;
io-channel-names = "buttons";
...
};
battery {
...
compatible = "ingenic,jz4740-battery";
io-channels = <&adc INGENIC_ADC_BATTERY>;
io-channel-names = "battery";
...
};
Nuvoton NPCM Analog to Digital Converter (ADC)
The NPCM ADC is a 10-bit converter for eight channel inputs.
Required properties:
- compatible: "nuvoton,npcm750-adc" for the NPCM7XX BMC.
- reg: specifies physical base address and size of the registers.
- interrupts: Contain the ADC interrupt with flags for falling edge.
Optional properties:
- clocks: phandle of ADC reference clock, in case the clock is not
added the ADC will use the default ADC sample rate.
- vref-supply: The regulator supply ADC reference voltage, in case the
vref-supply is not added the ADC will use internal voltage
reference.
Example:
adc: adc@f000c000 {
compatible = "nuvoton,npcm750-adc";
reg = <0xf000c000 0x8>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk NPCM7XX_CLK_ADC>;
};
......@@ -11,11 +11,13 @@ New driver handles the following
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
for exynos4412/5250 controllers.
for Exynos5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
Must be "samsung,exynos4212-adc" for
controllers compatible with ADC of Exynos4212 and Exynos4412.
Must be "samsung,exynos7-adc" for
the ADC in Exynos7 and compatibles
Must be "samsung,s3c2410-adc" for
......
* Texas Instruments' ads124s08 and ads124s06 ADC chip
Required properties:
- compatible :
"ti,ads124s08"
"ti,ads124s06"
- reg : spi chip select number for the device
Recommended properties:
- spi-max-frequency : Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
- spi-cpha : Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- reset-gpios : GPIO pin used to reset the device.
Example:
adc@0 {
compatible = "ti,ads124s08";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpha;
reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
};
Bosch Sensortec BME680 pressure/temperature/humidity/voc sensors
Required properties:
- compatible: must be "bosch,bme680"
Example:
bme680@76 {
compatible = "bosch,bme680";
reg = <0x76>;
};
* Plantower PMS7003 particulate matter sensor
Required properties:
- compatible: must be "plantower,pms7003"
- vcc-supply: phandle to the regulator that provides power to the sensor
Optional properties:
- plantower,set-gpios: phandle to the GPIO connected to the SET line
- reset-gpios: phandle to the GPIO connected to the RESET line
Refer to serial/slave-device.txt for generic serial attached device bindings.
Example:
&uart0 {
air-pollution-sensor {
compatible = "plantower,pms7003";
vcc-supply = <&reg_vcc5v0>;
};
};
* Sensirion SGP30/SGPC3 multi-pixel Gas Sensor
Required properties:
- compatible: must be one of
"sensirion,sgp30"
"sensirion,sgpc3"
- reg: the I2C address of the sensor
Example:
gas@58 {
compatible = "sensirion,sgp30";
reg = <0x58>;
};
* Sensirion SPS30 particulate matter sensor
Required properties:
- compatible: must be "sensirion,sps30"
- reg: the I2C address of the sensor
Example:
sps30@69 {
compatible = "sensirion,sps30";
reg = <0x69>;
};
* Texas Instruments Dual, 12-Bit Serial Input Digital-to-Analog Converter
The DAC7612 is a dual, 12-bit digital-to-analog converter (DAC) with guaranteed
12-bit monotonicity performance over the industrial temperature range.
Is is programmable through an SPI interface.
The internal DACs are loaded when the LOADDACS pin is pulled down.
http://www.ti.com/lit/ds/sbas106/sbas106.pdf
Required Properties:
- compatible: Should be one of:
"ti,dac7612"
"ti,dac7612u"
"ti,dac7612ub"
- reg: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt
Optional Properties:
- ti,loaddacs-gpios: GPIO descriptor for the LOADDACS pin.
- spi-*: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
dac@1 {
compatible = "ti,dac7612";
reg = <0x1>;
ti,loaddacs-gpios = <&msmgpio 25 GPIO_ACTIVE_LOW>;
};
Analog Devices AD5933/AD5934 Impedance Converter, Network Analyzer
https://www.analog.com/media/en/technical-documentation/data-sheets/AD5933.pdf
https://www.analog.com/media/en/technical-documentation/data-sheets/AD5934.pdf
Required properties:
- compatible : should be one of
"adi,ad5933"
"adi,ad5934"
- reg : the I2C address.
- vdd-supply : The regulator supply for DVDD, AVDD1 and AVDD2 when they
are connected together.
Optional properties:
- clocks : external clock reference.
- clock-names : must be "mclk" if clocks is set.
Example for a I2C device node:
impedance-analyzer@0d {
compatible = "adi,adxl345";
reg = <0x0d>;
vdd-supply = <&vdd_supply>;
clocks = <&ref_clk>;
clock-names = "mclk";
};
......@@ -9,9 +9,11 @@ Required properties:
- spi-max-frequency : set maximum clock frequency (only for SPI)
Optional properties:
- interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW
- interrupts : interrupt mapping for IRQ
- interrupt-names : set to "INT1" if INT1 pin should be used as interrupt
input, set to "INT2" if INT2 pin should be used instead
- drive-open-drain : set if the specified interrupt pin should be configured as
open drain. If not set, defaults to push-pull.
Examples:
......@@ -20,7 +22,7 @@ bmi160@68 {
reg = <0x68>;
interrupt-parent = <&gpio4>;
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
......
......@@ -11,6 +11,7 @@ Required properties:
"invensense,mpu9250"
"invensense,mpu9255"
"invensense,icm20608"
"invensense,icm20602"
- reg : the I2C address of the sensor
- interrupts: interrupt mapping for IRQ. It should be configured with flags
IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
......
* MAX44009 Ambient Light Sensor
Required properties:
- compatible: should be "maxim,max44009"
- reg: the I2C address of the device (default is <0x4a>)
Optional properties:
- interrupts: interrupt mapping for GPIO IRQ. Should be configured with
IRQ_TYPE_EDGE_FALLING.
Refer to interrupt-controller/interrupts.txt for generic interrupt client
node bindings.
Example:
light-sensor@4a {
compatible = "maxim,max44009";
reg = <0x4a>;
interrupt-parent = <&gpio1>;
interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
};
......@@ -77,3 +77,4 @@ Pressure sensors:
- st,lps22hb-press
- st,lps33hw
- st,lps35hw
- st,lps22hh
......@@ -310,6 +310,7 @@ phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
pine64 Pine64
pixcir PIXCIR MICROELECTRONICS Co., Ltd
plantower Plantower Co., Ltd
plathome Plat'Home Co., Ltd.
plda PLDA
plx Broadcom Corporation (formerly PLX Technology)
......
......@@ -854,6 +854,22 @@ S: Supported
F: drivers/iio/adc/ad7124.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt
ANALOG DEVICES INC AD7606 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7606.c
F: Documentation/devicetree/bindings/iio/adc/ad7606.txt
ANALOG DEVICES INC AD7768-1 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7768-1.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt
ANALOG DEVICES INC AD9389B DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
......@@ -14619,11 +14635,6 @@ L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/staging/wilc1000/
STAGING - XGI Z7,Z9,Z11 PCI DISPLAY DRIVER
M: Arnaud Patard <arnaud.patard@rtp-net.org>
S: Odd Fixes
F: drivers/staging/xgifb/
STAGING SUBSYSTEM
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
......@@ -15218,6 +15229,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/ti/
Texas Instruments' DAC7612 DAC Driver
M: Ricardo Ribalda <ricardo@ribalda.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/dac/ti-dac7612.c
F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
......
......@@ -150,8 +150,8 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
}
static int adxl345_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
s64 n;
......
......@@ -31,6 +31,7 @@
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
......@@ -107,6 +108,8 @@ struct mma8452_data {
u8 data_cfg;
const struct mma_chip_info *chip_info;
int sleep_val;
struct regulator *vdd_reg;
struct regulator *vddio_reg;
};
/**
......@@ -1534,9 +1537,39 @@ static int mma8452_probe(struct i2c_client *client,
mutex_init(&data->lock);
data->chip_info = match->data;
data->vdd_reg = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(data->vdd_reg)) {
if (PTR_ERR(data->vdd_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "failed to get VDD regulator!\n");
return PTR_ERR(data->vdd_reg);
}
data->vddio_reg = devm_regulator_get(&client->dev, "vddio");
if (IS_ERR(data->vddio_reg)) {
if (PTR_ERR(data->vddio_reg) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_err(&client->dev, "failed to get VDDIO regulator!\n");
return PTR_ERR(data->vddio_reg);
}
ret = regulator_enable(data->vdd_reg);
if (ret) {
dev_err(&client->dev, "failed to enable VDD regulator!\n");
return ret;
}
ret = regulator_enable(data->vddio_reg);
if (ret) {
dev_err(&client->dev, "failed to enable VDDIO regulator!\n");
goto disable_regulator_vdd;
}
ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
if (ret < 0)
return ret;
goto disable_regulators;
switch (ret) {
case MMA8451_DEVICE_ID:
......@@ -1549,7 +1582,8 @@ static int mma8452_probe(struct i2c_client *client,
break;
/* else: fall through */
default:
return -ENODEV;
ret = -ENODEV;
goto disable_regulators;
}
dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
......@@ -1566,13 +1600,13 @@ static int mma8452_probe(struct i2c_client *client,
ret = mma8452_reset(client);
if (ret < 0)
return ret;
goto disable_regulators;
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
data->data_cfg);
if (ret < 0)
return ret;
goto disable_regulators;
/*
* By default set transient threshold to max to avoid events if
......@@ -1581,7 +1615,7 @@ static int mma8452_probe(struct i2c_client *client,
ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
MMA8452_TRANSIENT_THS_MASK);
if (ret < 0)
return ret;
goto disable_regulators;
if (client->irq) {
int irq2;
......@@ -1595,7 +1629,7 @@ static int mma8452_probe(struct i2c_client *client,
MMA8452_CTRL_REG5,
data->chip_info->all_events);
if (ret < 0)
return ret;
goto disable_regulators;
dev_dbg(&client->dev, "using interrupt line INT1\n");
}
......@@ -1604,11 +1638,11 @@ static int mma8452_probe(struct i2c_client *client,
MMA8452_CTRL_REG4,
data->chip_info->enabled_events);
if (ret < 0)
return ret;
goto disable_regulators;
ret = mma8452_trigger_setup(indio_dev);
if (ret < 0)
return ret;
goto disable_regulators;
}
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
......@@ -1661,12 +1695,19 @@ static int mma8452_probe(struct i2c_client *client,
trigger_cleanup:
mma8452_trigger_cleanup(indio_dev);
disable_regulators:
regulator_disable(data->vddio_reg);
disable_regulator_vdd:
regulator_disable(data->vdd_reg);
return ret;
}
static int mma8452_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma8452_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
......@@ -1678,6 +1719,9 @@ static int mma8452_remove(struct i2c_client *client)
mma8452_trigger_cleanup(indio_dev);
mma8452_standby(iio_priv(indio_dev));
regulator_disable(data->vddio_reg);
regulator_disable(data->vdd_reg);
return 0;
}
......@@ -1696,6 +1740,18 @@ static int mma8452_runtime_suspend(struct device *dev)
return -EAGAIN;
}
ret = regulator_disable(data->vddio_reg);
if (ret) {
dev_err(dev, "failed to disable VDDIO regulator\n");
return ret;
}
ret = regulator_disable(data->vdd_reg);
if (ret) {
dev_err(dev, "failed to disable VDD regulator\n");
return ret;
}
return 0;
}
......@@ -1705,9 +1761,22 @@ static int mma8452_runtime_resume(struct device *dev)
struct mma8452_data *data = iio_priv(indio_dev);
int ret, sleep_val;
ret = regulator_enable(data->vdd_reg);
if (ret) {
dev_err(dev, "failed to enable VDD regulator\n");
return ret;
}
ret = regulator_enable(data->vddio_reg);
if (ret) {
dev_err(dev, "failed to enable VDDIO regulator\n");
regulator_disable(data->vdd_reg);
return ret;
}
ret = mma8452_active(data);
if (ret < 0)
return ret;
goto runtime_resume_failed;
ret = mma8452_get_odr_index(data);
sleep_val = 1000 / mma8452_samp_freq[ret][0];
......@@ -1717,25 +1786,17 @@ static int mma8452_runtime_resume(struct device *dev)
msleep_interruptible(sleep_val);
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int mma8452_suspend(struct device *dev)
{
return mma8452_standby(iio_priv(i2c_get_clientdata(
to_i2c_client(dev))));
}
runtime_resume_failed:
regulator_disable(data->vddio_reg);
regulator_disable(data->vdd_reg);
static int mma8452_resume(struct device *dev)
{
return mma8452_active(iio_priv(i2c_get_clientdata(
to_i2c_client(dev))));
return ret;
}
#endif
static const struct dev_pm_ops mma8452_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(mma8452_runtime_suspend,
mma8452_runtime_resume, NULL)
};
......
......@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mutex.h>
......@@ -918,12 +919,167 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
#define ST_ACCEL_TRIGGER_OPS NULL
#endif
static const struct iio_mount_matrix *
get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
return adata->mount_matrix;
}
static const struct iio_chan_spec_ext_info mount_matrix_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, get_mount_matrix),
{ },
};
/* Read ST-specific _ONT orientation data from ACPI and generate an
* appropriate mount matrix.
*/
static int apply_acpi_orientation(struct iio_dev *indio_dev,
struct iio_chan_spec *channels)
{
#ifdef CONFIG_ACPI
struct st_sensor_data *adata = iio_priv(indio_dev);
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_device *adev;
union acpi_object *ont;
union acpi_object *elements;
acpi_status status;
int ret = -EINVAL;
unsigned int val;
int i, j;
int final_ont[3][3] = { { 0 }, };
/* For some reason, ST's _ONT translation does not apply directly
* to the data read from the sensor. Another translation must be
* performed first, as described by the matrix below. Perhaps
* ST required this specific translation for the first product
* where the device was mounted?
*/
const int default_ont[3][3] = {
{ 0, 1, 0 },
{ -1, 0, 0 },
{ 0, 0, -1 },
};
adev = ACPI_COMPANION(adata->dev);
if (!adev)
return 0;
/* Read _ONT data, which should be a package of 6 integers. */
status = acpi_evaluate_object(adev->handle, "_ONT", NULL, &buffer);
if (status == AE_NOT_FOUND) {
return 0;
} else if (ACPI_FAILURE(status)) {
dev_warn(&indio_dev->dev, "failed to execute _ONT: %d\n",
status);
return status;
}
ont = buffer.pointer;
if (ont->type != ACPI_TYPE_PACKAGE || ont->package.count != 6)
goto out;
/* The first 3 integers provide axis order information.
* e.g. 0 1 2 would indicate normal X,Y,Z ordering.
* e.g. 1 0 2 indicates that data arrives in order Y,X,Z.
*/
elements = ont->package.elements;
for (i = 0; i < 3; i++) {
if (elements[i].type != ACPI_TYPE_INTEGER)
goto out;
val = elements[i].integer.value;
if (val < 0 || val > 2)
goto out;
/* Avoiding full matrix multiplication, we simply reorder the
* columns in the default_ont matrix according to the
* ordering provided by _ONT.
*/
final_ont[0][i] = default_ont[0][val];
final_ont[1][i] = default_ont[1][val];
final_ont[2][i] = default_ont[2][val];
}
/* The final 3 integers provide sign flip information.
* 0 means no change, 1 means flip.
* e.g. 0 0 1 means that Z data should be sign-flipped.
* This is applied after the axis reordering from above.
*/
elements += 3;
for (i = 0; i < 3; i++) {
if (elements[i].type != ACPI_TYPE_INTEGER)
goto out;
val = elements[i].integer.value;
if (val != 0 && val != 1)
goto out;
if (!val)
continue;
/* Flip the values in the indicated column */
final_ont[0][i] *= -1;
final_ont[1][i] *= -1;
final_ont[2][i] *= -1;
}
/* Convert our integer matrix to a string-based iio_mount_matrix */
adata->mount_matrix = devm_kmalloc(&indio_dev->dev,
sizeof(*adata->mount_matrix),
GFP_KERNEL);
if (!adata->mount_matrix) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
int matrix_val = final_ont[i][j];
char *str_value;
switch (matrix_val) {
case -1:
str_value = "-1";
break;
case 0:
str_value = "0";
break;
case 1:
str_value = "1";
break;
default:
goto out;
}
adata->mount_matrix->rotation[i * 3 + j] = str_value;
}
}
/* Expose the mount matrix via ext_info */
for (i = 0; i < indio_dev->num_channels; i++)
channels[i].ext_info = mount_matrix_ext_info;
ret = 0;
dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n");
out:
kfree(buffer.pointer);
return ret;
#else /* !CONFIG_ACPI */
return 0;
#endif
}
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)adata->dev->platform_data;
int irq = adata->get_irq_data_ready(indio_dev);
struct iio_chan_spec *channels;
size_t channels_size;
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
......@@ -942,9 +1098,22 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
adata->multiread_bit = adata->sensor_settings->multi_read_bit;
indio_dev->channels = adata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec);
channels = devm_kmemdup(&indio_dev->dev,
adata->sensor_settings->ch,
channels_size, GFP_KERNEL);
if (!channels) {
err = -ENOMEM;
goto st_accel_power_off;
}
if (apply_acpi_orientation(indio_dev, channels))
dev_warn(&indio_dev->dev,
"failed to apply ACPI orientation data: %d\n", err);
indio_dev->channels = channels;
adata->current_fullscale = (struct st_sensor_fullscale_avl *)
&adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
......
......@@ -57,18 +57,48 @@ config AD7298
module will be called ad7298.
config AD7476
tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD an TI"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
Say yes here to build support for the following SPI analog to
digital converters (ADCs):
Analog Devices: AD7273, AD7274, AD7276, AD7277, AD7278, AD7475,
AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495, AD7910,
AD7920.
Texas Instruments: ADS7866, ADS7867, ADS7868.
To compile this driver as a module, choose M here: the
module will be called ad7476.
config AD7606
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7606_IFACE_PARALLEL
tristate "Analog Devices AD7606 ADC driver with parallel interface support"
depends on HAS_IOMEM
select AD7606
help
Say yes here to build parallel interface support for Analog Devices:
ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
To compile this driver as a module, choose M here: the
module will be called ad7606_parallel.
config AD7606_IFACE_SPI
tristate "Analog Devices AD7606 ADC driver with spi interface support"
depends on SPI
select AD7606
help
Say yes here to build spi interface support for Analog Devices:
ad7605-4, ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
To compile this driver as a module, choose M here: the
module will be called ad7606_spi.
config AD7766
tristate "Analog Devices AD7766/AD7767 ADC driver"
depends on SPI_MASTER
......@@ -81,6 +111,19 @@ config AD7766
To compile this driver as a module, choose M here: the module will be
called ad7766.
config AD7768_1
tristate "Analog Devices AD7768-1 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7768-1 SPI
simultaneously sampling sigma-delta analog to digital converter (ADC).
To compile this driver as a module, choose M here: the module will be
called ad7768-1.
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
......@@ -367,6 +410,15 @@ config INA2XX_ADC
Say yes here to build support for TI INA2xx family of Power Monitors.
This driver is mutually exclusive with the HWMON version.
config INGENIC_ADC
tristate "Ingenic JZ47xx SoCs ADC driver"
depends on MIPS || COMPILE_TEST
help
Say yes here to build support for the Ingenic JZ47xx SoCs ADC unit.
This driver can also be built as a module. If so, the module will be
called ingenic_adc.
config IMX7D_ADC
tristate "Freescale IMX7D ADC driver"
depends on ARCH_MXC || COMPILE_TEST
......@@ -576,6 +628,16 @@ config NAU7802
To compile this driver as a module, choose M here: the
module will be called nau7802.
config NPCM_ADC
tristate "Nuvoton NPCM ADC driver"
depends on ARCH_NPCM || COMPILE_TEST
depends on HAS_IOMEM
help
Say yes here to build support for Nuvoton NPCM ADC.
This driver can also be built as a module. If so, the module
will be called npcm_adc.
config PALMAS_GPADC
tristate "TI Palmas General Purpose ADC"
depends on MFD_PALMAS
......@@ -908,6 +970,16 @@ config TI_ADS8688
This driver can also be built as a module. If so, the module will be
called ti-ads8688.
config TI_ADS124S08
tristate "Texas Instruments ADS124S08"
depends on SPI && OF
help
If you say yes here you get support for Texas Instruments ADS124S08
and ADS124S06 ADC chips
This driver can also be built as a module. If so, the module will be
called ti-ads124s08.
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC && HAS_DMA
......
......@@ -11,7 +11,11 @@ obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
obj-$(CONFIG_AD7606) += ad7606.o
obj-$(CONFIG_AD7766) += ad7766.o
obj-$(CONFIG_AD7768_1) += ad7768-1.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
......@@ -36,6 +40,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
......@@ -55,6 +60,7 @@ 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_NPCM_ADC) += npcm_adc.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
......@@ -81,6 +87,7 @@ obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
......
......@@ -59,6 +59,9 @@ enum ad7476_supported_device_ids {
ID_ADC081S,
ID_ADC101S,
ID_ADC121S,
ID_ADS7866,
ID_ADS7867,
ID_ADS7868,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
......@@ -157,6 +160,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
#define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7091R] = {
......@@ -209,6 +214,18 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = ADC081S_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_ADS7866] = {
.channel[0] = ADS786X_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_ADS7867] = {
.channel[0] = ADS786X_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_ADS7868] = {
.channel[0] = ADS786X_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
};
static const struct iio_info ad7476_info = {
......@@ -314,6 +331,9 @@ static const struct spi_device_id ad7476_id[] = {
{"adc081s", ID_ADC081S},
{"adc101s", ID_ADC101S},
{"adc121s", ID_ADC121S},
{"ads7866", ID_ADS7866},
{"ads7867", ID_ADS7867},
{"ads7868", ID_ADS7868},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AD7606 ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#ifndef IIO_ADC_AD7606_H_
......@@ -15,7 +14,6 @@
* @num_channels: number of channels
* @has_oversampling: whether the device has oversampling support
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
......@@ -27,13 +25,9 @@ struct ad7606_chip_info {
* @dev pointer to kernel device
* @chip_info entry in the table of chips that describes this device
* @reg regulator info for the the power supply of the device
* @poll_work work struct for continuously reading data from the device
* into an IIO triggered buffer
* @wq_data_avail wait queue struct for buffer mode
* @bops bus operations (SPI or parallel)
* @range voltage range selection, selects which scale to apply
* @oversampling oversampling selection
* @done marks whether reading data is done
* @base_address address from where to read data in parallel operation
* @lock protect sensor state from concurrent accesses to GPIOs
* @gpio_convst GPIO descriptor for conversion start signal (CONVST)
......@@ -44,19 +38,17 @@ struct ad7606_chip_info {
* @gpio_frstdata GPIO descriptor for reading from device when data
* is being read on the first channel
* @gpio_os GPIO descriptors to control oversampling on the device
* @complete completion to indicate end of conversion
* @trig The IIO trigger associated with the device.
* @data buffer for reading data from the device
*/
struct ad7606_state {
struct device *dev;
const struct ad7606_chip_info *chip_info;
struct regulator *reg;
struct work_struct poll_work;
wait_queue_head_t wq_data_avail;
const struct ad7606_bus_ops *bops;
unsigned int range;
unsigned int oversampling;
bool done;
void __iomem *base_address;
struct mutex lock; /* protect sensor state */
......@@ -66,6 +58,8 @@ struct ad7606_state {
struct gpio_desc *gpio_standby;
struct gpio_desc *gpio_frstdata;
struct gpio_descs *gpio_os;
struct iio_trigger *trig;
struct completion completion;
/*
* DMA (thus cache coherency maintenance) requires the
......@@ -87,7 +81,6 @@ struct ad7606_bus_ops {
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id,
const struct ad7606_bus_ops *bops);
int ad7606_remove(struct device *dev, int irq);
enum ad7606_supported_device_ids {
ID_AD7605_4,
......
// SPDX-License-Identifier: GPL-2.0
/*
* AD7606 Parallel Interface ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/module.h>
......@@ -27,7 +26,7 @@ static int ad7606_par16_read_block(struct device *dev,
}
static const struct ad7606_bus_ops ad7606_par16_bops = {
.read_block = ad7606_par16_read_block,
.read_block = ad7606_par16_read_block,
};
static int ad7606_par8_read_block(struct device *dev,
......@@ -42,7 +41,7 @@ static int ad7606_par8_read_block(struct device *dev,
}
static const struct ad7606_bus_ops ad7606_par8_bops = {
.read_block = ad7606_par8_read_block,
.read_block = ad7606_par8_read_block,
};
static int ad7606_par_probe(struct platform_device *pdev)
......@@ -72,40 +71,33 @@ static int ad7606_par_probe(struct platform_device *pdev)
&ad7606_par8_bops);
}
static int ad7606_par_remove(struct platform_device *pdev)
{
return ad7606_remove(&pdev->dev, platform_get_irq(pdev, 0));
}
static const struct platform_device_id ad7606_driver_ids[] = {
{
.name = "ad7605-4",
.driver_data = ID_AD7605_4,
}, {
.name = "ad7606-8",
.driver_data = ID_AD7606_8,
}, {
.name = "ad7606-6",
.driver_data = ID_AD7606_6,
}, {
.name = "ad7606-4",
.driver_data = ID_AD7606_4,
},
{ .name = "ad7605-4", .driver_data = ID_AD7605_4, },
{ .name = "ad7606-4", .driver_data = ID_AD7606_4, },
{ .name = "ad7606-6", .driver_data = ID_AD7606_6, },
{ .name = "ad7606-8", .driver_data = ID_AD7606_8, },
{ }
};
MODULE_DEVICE_TABLE(platform, ad7606_driver_ids);
static const struct of_device_id ad7606_of_match[] = {
{ .compatible = "adi,ad7605-4" },
{ .compatible = "adi,ad7606-4" },
{ .compatible = "adi,ad7606-6" },
{ .compatible = "adi,ad7606-8" },
{ },
};
MODULE_DEVICE_TABLE(of, ad7606_of_match);
static struct platform_driver ad7606_driver = {
.probe = ad7606_par_probe,
.remove = ad7606_par_remove,
.id_table = ad7606_driver_ids,
.driver = {
.name = "ad7606",
.pm = AD7606_PM_OPS,
.name = "ad7606",
.pm = AD7606_PM_OPS,
.of_match_table = ad7606_of_match,
},
};
module_platform_driver(ad7606_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
......
// SPDX-License-Identifier: GPL-2.0
/*
* AD7606 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
#include <linux/module.h>
......@@ -37,7 +36,7 @@ static int ad7606_spi_read_block(struct device *dev,
}
static const struct ad7606_bus_ops ad7606_spi_bops = {
.read_block = ad7606_spi_read_block,
.read_block = ad7606_spi_read_block,
};
static int ad7606_spi_probe(struct spi_device *spi)
......@@ -49,28 +48,32 @@ static int ad7606_spi_probe(struct spi_device *spi)
&ad7606_spi_bops);
}
static int ad7606_spi_remove(struct spi_device *spi)
{
return ad7606_remove(&spi->dev, spi->irq);
}
static const struct spi_device_id ad7606_id[] = {
{"ad7605-4", ID_AD7605_4},
{"ad7606-8", ID_AD7606_8},
{"ad7606-6", ID_AD7606_6},
{"ad7606-4", ID_AD7606_4},
static const struct spi_device_id ad7606_id_table[] = {
{ "ad7605-4", ID_AD7605_4 },
{ "ad7606-4", ID_AD7606_4 },
{ "ad7606-6", ID_AD7606_6 },
{ "ad7606-8", ID_AD7606_8 },
{}
};
MODULE_DEVICE_TABLE(spi, ad7606_id);
MODULE_DEVICE_TABLE(spi, ad7606_id_table);
static const struct of_device_id ad7606_of_match[] = {
{ .compatible = "adi,ad7605-4" },
{ .compatible = "adi,ad7606-4" },
{ .compatible = "adi,ad7606-6" },
{ .compatible = "adi,ad7606-8" },
{ },
};
MODULE_DEVICE_TABLE(of, ad7606_of_match);
static struct spi_driver ad7606_driver = {
.driver = {
.name = "ad7606",
.of_match_table = ad7606_of_match,
.pm = AD7606_PM_OPS,
},
.probe = ad7606_spi_probe,
.remove = ad7606_spi_remove,
.id_table = ad7606_id,
.id_table = ad7606_id_table,
};
module_spi_driver(ad7606_driver);
......
This diff is collapsed.
......@@ -115,6 +115,7 @@
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
#define MAX_EXYNOS4212_ADC_CHANNELS 4
#define MAX_S5PV210_ADC_CHANNELS 10
/* Bit definitions common for ADC_V1 and ADC_V2 */
......@@ -271,6 +272,19 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info,
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
/* Exynos4212 and 4412 is like ADCv1 but with four channels only */
static const struct exynos_adc_data exynos4212_adc_data = {
.num_channels = MAX_EXYNOS4212_ADC_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_adc_phy = true,
.phy_offset = EXYNOS_ADCV1_PHY_OFFSET,
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_v1_start_conv,
};
static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
......@@ -492,6 +506,9 @@ static const struct of_device_id exynos_adc_match[] = {
}, {
.compatible = "samsung,s5pv210-adc",
.data = &exynos_adc_s5pv210_data,
}, {
.compatible = "samsung,exynos4212-adc",
.data = &exynos4212_adc_data,
}, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
......@@ -929,7 +946,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
if (IS_REACHABLE(CONFIG_INPUT)) {
if (IS_REACHABLE(CONFIG_INPUT) && info->input) {
free_irq(info->tsirq, info);
input_unregister_device(info->input);
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* ADC driver for the Ingenic JZ47xx SoCs
* Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu>
*
* based on drivers/mfd/jz4740-adc.c
*/
#include <dt-bindings/iio/adc/ingenic,adc.h>
#include <linux/clk.h>
#include <linux/iio/iio.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#define JZ_ADC_REG_ENABLE 0x00
#define JZ_ADC_REG_CFG 0x04
#define JZ_ADC_REG_CTRL 0x08
#define JZ_ADC_REG_STATUS 0x0c
#define JZ_ADC_REG_ADTCH 0x18
#define JZ_ADC_REG_ADBDAT 0x1c
#define JZ_ADC_REG_ADSDAT 0x20
#define JZ_ADC_REG_CFG_BAT_MD BIT(4)
#define JZ_ADC_AUX_VREF 3300
#define JZ_ADC_AUX_VREF_BITS 12
#define JZ_ADC_BATTERY_LOW_VREF 2500
#define JZ_ADC_BATTERY_LOW_VREF_BITS 12
#define JZ4725B_ADC_BATTERY_HIGH_VREF 7500
#define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
#define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
#define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
struct ingenic_adc_soc_data {
unsigned int battery_high_vref;
unsigned int battery_high_vref_bits;
const int *battery_raw_avail;
size_t battery_raw_avail_size;
const int *battery_scale_avail;
size_t battery_scale_avail_size;
};
struct ingenic_adc {
void __iomem *base;
struct clk *clk;
struct mutex lock;
const struct ingenic_adc_soc_data *soc_data;
bool low_vref_mode;
};
static void ingenic_adc_set_config(struct ingenic_adc *adc,
uint32_t mask,
uint32_t val)
{
uint32_t cfg;
clk_enable(adc->clk);
mutex_lock(&adc->lock);
cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
cfg |= val;
writel(cfg, adc->base + JZ_ADC_REG_CFG);
mutex_unlock(&adc->lock);
clk_disable(adc->clk);
}
static void ingenic_adc_enable(struct ingenic_adc *adc,
int engine,
bool enabled)
{
u8 val;
mutex_lock(&adc->lock);
val = readb(adc->base + JZ_ADC_REG_ENABLE);
if (enabled)
val |= BIT(engine);
else
val &= ~BIT(engine);
writeb(val, adc->base + JZ_ADC_REG_ENABLE);
mutex_unlock(&adc->lock);
}
static int ingenic_adc_capture(struct ingenic_adc *adc,
int engine)
{
u8 val;
int ret;
ingenic_adc_enable(adc, engine, true);
ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
!(val & BIT(engine)), 250, 1000);
if (ret)
ingenic_adc_enable(adc, engine, false);
return ret;
}
static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
switch (m) {
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case INGENIC_ADC_BATTERY:
if (val > JZ_ADC_BATTERY_LOW_VREF) {
ingenic_adc_set_config(adc,
JZ_ADC_REG_CFG_BAT_MD,
0);
adc->low_vref_mode = false;
} else {
ingenic_adc_set_config(adc,
JZ_ADC_REG_CFG_BAT_MD,
JZ_ADC_REG_CFG_BAT_MD);
adc->low_vref_mode = true;
}
return 0;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const int jz4725b_adc_battery_raw_avail[] = {
0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
};
static const int jz4725b_adc_battery_scale_avail[] = {
JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
};
static const int jz4740_adc_battery_raw_avail[] = {
0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
};
static const int jz4740_adc_battery_scale_avail[] = {
JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
};
static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
.battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
.battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
.battery_raw_avail = jz4725b_adc_battery_raw_avail,
.battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
.battery_scale_avail = jz4725b_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
};
static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
.battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
.battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
.battery_raw_avail = jz4740_adc_battery_raw_avail,
.battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
.battery_scale_avail = jz4740_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
};
static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
const int **vals,
int *type,
int *length,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
*type = IIO_VAL_INT;
*length = adc->soc_data->battery_raw_avail_size;
*vals = adc->soc_data->battery_raw_avail;
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_FRACTIONAL_LOG2;
*length = adc->soc_data->battery_scale_avail_size;
*vals = adc->soc_data->battery_scale_avail;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
};
}
static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
clk_enable(adc->clk);
ret = ingenic_adc_capture(adc, chan->channel);
if (ret) {
clk_disable(adc->clk);
return ret;
}
switch (chan->channel) {
case INGENIC_ADC_AUX:
*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
break;
case INGENIC_ADC_BATTERY:
*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
break;
}
clk_disable(adc->clk);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case INGENIC_ADC_AUX:
*val = JZ_ADC_AUX_VREF;
*val2 = JZ_ADC_AUX_VREF_BITS;
break;
case INGENIC_ADC_BATTERY:
if (adc->low_vref_mode) {
*val = JZ_ADC_BATTERY_LOW_VREF;
*val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
} else {
*val = adc->soc_data->battery_high_vref;
*val2 = adc->soc_data->battery_high_vref_bits;
}
break;
}
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static void ingenic_adc_clk_cleanup(void *data)
{
clk_unprepare(data);
}
static const struct iio_info ingenic_adc_info = {
.write_raw = ingenic_adc_write_raw,
.read_raw = ingenic_adc_read_raw,
.read_avail = ingenic_adc_read_avail,
};
static const struct iio_chan_spec ingenic_channels[] = {
{
.extend_name = "aux",
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = INGENIC_ADC_AUX,
},
{
.extend_name = "battery",
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = INGENIC_ADC_BATTERY,
},
};
static int ingenic_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct iio_dev *iio_dev;
struct ingenic_adc *adc;
struct resource *mem_base;
const struct ingenic_adc_soc_data *soc_data;
int ret;
soc_data = device_get_match_data(dev);
if (!soc_data)
return -EINVAL;
iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!iio_dev)
return -ENOMEM;
adc = iio_priv(iio_dev);
mutex_init(&adc->lock);
adc->soc_data = soc_data;
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(dev, mem_base);
if (IS_ERR(adc->base)) {
dev_err(dev, "Unable to ioremap mmio resource\n");
return PTR_ERR(adc->base);
}
adc->clk = devm_clk_get(dev, "adc");
if (IS_ERR(adc->clk)) {
dev_err(dev, "Unable to get clock\n");
return PTR_ERR(adc->clk);
}
ret = clk_prepare_enable(adc->clk);
if (ret) {
dev_err(dev, "Failed to enable clock\n");
return ret;
}
/* Put hardware in a known passive state. */
writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
clk_disable(adc->clk);
ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
if (ret) {
dev_err(dev, "Unable to add action\n");
return ret;
}
iio_dev->dev.parent = dev;
iio_dev->name = "jz-adc";
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = ingenic_channels;
iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
iio_dev->info = &ingenic_adc_info;
ret = devm_iio_device_register(dev, iio_dev);
if (ret)
dev_err(dev, "Unable to register IIO device\n");
return ret;
}
#ifdef CONFIG_OF
static const struct of_device_id ingenic_adc_of_match[] = {
{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
{ },
};
MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
#endif
static struct platform_driver ingenic_adc_driver = {
.driver = {
.name = "ingenic-adc",
.of_match_table = of_match_ptr(ingenic_adc_of_match),
},
.probe = ingenic_adc_probe,
};
module_platform_driver(ingenic_adc_driver);
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0+
/*
* lpc32xx_adc.c - Support for ADC in LPC32XX
*
* 3-channel, 10-bit ADC
*
* Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
......
......@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/syscon.h>
#define MESON_SAR_ADC_REG0 0x00
#define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
......@@ -174,6 +175,9 @@
#define MESON_SAR_ADC_EFUSE_BYTE3_UPPER_ADC_VAL GENMASK(6, 0)
#define MESON_SAR_ADC_EFUSE_BYTE3_IS_CALIBRATED BIT(7)
#define MESON_HHI_DPLL_TOP_0 0x318
#define MESON_HHI_DPLL_TOP_0_TSC_BIT4 BIT(9)
/* for use with IIO_VAL_INT_PLUS_MICRO */
#define MILLION 1000000
......@@ -280,6 +284,7 @@ struct meson_sar_adc_priv {
struct completion done;
int calibbias;
int calibscale;
struct regmap *tsc_regmap;
bool temperature_sensor_calibrated;
u8 temperature_sensor_coefficient;
u16 temperature_sensor_adc_val;
......@@ -727,6 +732,15 @@ static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
return ret;
}
priv->tsc_regmap =
syscon_regmap_lookup_by_phandle(indio_dev->dev.parent->of_node,
"amlogic,hhi-sysctrl");
if (IS_ERR(priv->tsc_regmap)) {
dev_err(indio_dev->dev.parent,
"failed to get amlogic,hhi-sysctrl regmap\n");
return PTR_ERR(priv->tsc_regmap);
}
read_len = MESON_SAR_ADC_EFUSE_BYTES;
buf = nvmem_cell_read(temperature_calib, &read_len);
if (IS_ERR(buf)) {
......@@ -861,6 +875,22 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
priv->temperature_sensor_coefficient);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_C_MASK, regval);
if (priv->param->temperature_trimming_bits == 5) {
if (priv->temperature_sensor_coefficient & BIT(4))
regval = MESON_HHI_DPLL_TOP_0_TSC_BIT4;
else
regval = 0;
/*
* bit [4] (the 5th bit when starting to count at 1)
* of the TSC is located in the HHI register area.
*/
regmap_update_bits(priv->tsc_regmap,
MESON_HHI_DPLL_TOP_0,
MESON_HHI_DPLL_TOP_0_TSC_BIT4,
regval);
}
} else {
regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
MESON_SAR_ADC_DELTA_10_TS_REVE1, 0);
......@@ -1064,6 +1094,9 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = {
.bandgap_reg = MESON_SAR_ADC_DELTA_10,
.regmap_config = &meson_sar_adc_regmap_config_meson8,
.resolution = 10,
.temperature_trimming_bits = 5,
.temperature_multiplier = 10,
.temperature_divider = 32,
};
static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = {
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Nuvoton Technology corporation.
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/mfd/syscon.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
struct npcm_adc {
bool int_status;
u32 adc_sample_hz;
struct device *dev;
void __iomem *regs;
struct clk *adc_clk;
wait_queue_head_t wq;
struct regulator *vref;
struct regmap *rst_regmap;
};
/* NPCM7xx reset module */
#define NPCM7XX_IPSRST1_OFFSET 0x020
#define NPCM7XX_IPSRST1_ADC_RST BIT(27)
/* ADC registers */
#define NPCM_ADCCON 0x00
#define NPCM_ADCDATA 0x04
/* ADCCON Register Bits */
#define NPCM_ADCCON_ADC_INT_EN BIT(21)
#define NPCM_ADCCON_REFSEL BIT(19)
#define NPCM_ADCCON_ADC_INT_ST BIT(18)
#define NPCM_ADCCON_ADC_EN BIT(17)
#define NPCM_ADCCON_ADC_RST BIT(16)
#define NPCM_ADCCON_ADC_CONV BIT(13)
#define NPCM_ADCCON_CH_MASK GENMASK(27, 24)
#define NPCM_ADCCON_CH(x) ((x) << 24)
#define NPCM_ADCCON_DIV_SHIFT 1
#define NPCM_ADCCON_DIV_MASK GENMASK(8, 1)
#define NPCM_ADC_DATA_MASK(x) ((x) & GENMASK(9, 0))
#define NPCM_ADC_ENABLE (NPCM_ADCCON_ADC_EN | NPCM_ADCCON_ADC_INT_EN)
/* ADC General Definition */
#define NPCM_RESOLUTION_BITS 10
#define NPCM_INT_VREF_MV 2000
#define NPCM_ADC_CHAN(ch) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = ch, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec npcm_adc_iio_channels[] = {
NPCM_ADC_CHAN(0),
NPCM_ADC_CHAN(1),
NPCM_ADC_CHAN(2),
NPCM_ADC_CHAN(3),
NPCM_ADC_CHAN(4),
NPCM_ADC_CHAN(5),
NPCM_ADC_CHAN(6),
NPCM_ADC_CHAN(7),
};
static irqreturn_t npcm_adc_isr(int irq, void *data)
{
u32 regtemp;
struct iio_dev *indio_dev = data;
struct npcm_adc *info = iio_priv(indio_dev);
regtemp = ioread32(info->regs + NPCM_ADCCON);
if (regtemp & NPCM_ADCCON_ADC_INT_ST) {
iowrite32(regtemp, info->regs + NPCM_ADCCON);
wake_up_interruptible(&info->wq);
info->int_status = true;
}
return IRQ_HANDLED;
}
static int npcm_adc_read(struct npcm_adc *info, int *val, u8 channel)
{
int ret;
u32 regtemp;
/* Select ADC channel */
regtemp = ioread32(info->regs + NPCM_ADCCON);
regtemp &= ~NPCM_ADCCON_CH_MASK;
info->int_status = false;
iowrite32(regtemp | NPCM_ADCCON_CH(channel) |
NPCM_ADCCON_ADC_CONV, info->regs + NPCM_ADCCON);
ret = wait_event_interruptible_timeout(info->wq, info->int_status,
msecs_to_jiffies(10));
if (ret == 0) {
regtemp = ioread32(info->regs + NPCM_ADCCON);
if ((regtemp & NPCM_ADCCON_ADC_CONV) && info->rst_regmap) {
/* if conversion failed - reset ADC module */
regmap_write(info->rst_regmap, NPCM7XX_IPSRST1_OFFSET,
NPCM7XX_IPSRST1_ADC_RST);
msleep(100);
regmap_write(info->rst_regmap, NPCM7XX_IPSRST1_OFFSET,
0x0);
msleep(100);
/* Enable ADC and start conversion module */
iowrite32(NPCM_ADC_ENABLE | NPCM_ADCCON_ADC_CONV,
info->regs + NPCM_ADCCON);
dev_err(info->dev, "RESET ADC Complete\n");
}
return -ETIMEDOUT;
}
if (ret < 0)
return ret;
*val = NPCM_ADC_DATA_MASK(ioread32(info->regs + NPCM_ADCDATA));
return 0;
}
static int npcm_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
int ret;
int vref_uv;
struct npcm_adc *info = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = npcm_adc_read(info, val, chan->channel);
mutex_unlock(&indio_dev->mlock);
if (ret) {
dev_err(info->dev, "NPCM ADC read failed\n");
return ret;
}
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (info->vref) {
vref_uv = regulator_get_voltage(info->vref);
*val = vref_uv / 1000;
} else {
*val = NPCM_INT_VREF_MV;
}
*val2 = NPCM_RESOLUTION_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = info->adc_sample_hz;
return IIO_VAL_INT;
default:
return -EINVAL;
}
return 0;
}
static const struct iio_info npcm_adc_iio_info = {
.read_raw = &npcm_adc_read_raw,
};
static const struct of_device_id npcm_adc_match[] = {
{ .compatible = "nuvoton,npcm750-adc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, npcm_adc_match);
static int npcm_adc_probe(struct platform_device *pdev)
{
int ret;
int irq;
u32 div;
u32 reg_con;
struct resource *res;
struct npcm_adc *info;
struct iio_dev *indio_dev;
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
if (!indio_dev)
return -ENOMEM;
info = iio_priv(indio_dev);
info->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->regs))
return PTR_ERR(info->regs);
info->adc_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->adc_clk)) {
dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
return PTR_ERR(info->adc_clk);
}
/* calculate ADC clock sample rate */
reg_con = ioread32(info->regs + NPCM_ADCCON);
div = reg_con & NPCM_ADCCON_DIV_MASK;
div = div >> NPCM_ADCCON_DIV_SHIFT;
info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
if (of_device_is_compatible(np, "nuvoton,npcm750-adc")) {
info->rst_regmap = syscon_regmap_lookup_by_compatible
("nuvoton,npcm750-rst");
if (IS_ERR(info->rst_regmap)) {
dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-rst\n");
ret = PTR_ERR(info->rst_regmap);
goto err_disable_clk;
}
}
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "failed getting interrupt resource\n");
ret = -EINVAL;
goto err_disable_clk;
}
ret = devm_request_irq(&pdev->dev, irq, npcm_adc_isr, 0,
"NPCM_ADC", indio_dev);
if (ret < 0) {
dev_err(dev, "failed requesting interrupt\n");
goto err_disable_clk;
}
reg_con = ioread32(info->regs + NPCM_ADCCON);
info->vref = devm_regulator_get_optional(&pdev->dev, "vref");
if (!IS_ERR(info->vref)) {
ret = regulator_enable(info->vref);
if (ret) {
dev_err(&pdev->dev, "Can't enable ADC reference voltage\n");
goto err_disable_clk;
}
iowrite32(reg_con & ~NPCM_ADCCON_REFSEL,
info->regs + NPCM_ADCCON);
} else {
/*
* Any error which is not ENODEV indicates the regulator
* has been specified and so is a failure case.
*/
if (PTR_ERR(info->vref) != -ENODEV) {
ret = PTR_ERR(info->vref);
goto err_disable_clk;
}
/* Use internal reference */
iowrite32(reg_con | NPCM_ADCCON_REFSEL,
info->regs + NPCM_ADCCON);
}
init_waitqueue_head(&info->wq);
reg_con = ioread32(info->regs + NPCM_ADCCON);
reg_con |= NPCM_ADC_ENABLE;
/* Enable the ADC Module */
iowrite32(reg_con, info->regs + NPCM_ADCCON);
/* Start ADC conversion */
iowrite32(reg_con | NPCM_ADCCON_ADC_CONV, info->regs + NPCM_ADCCON);
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &npcm_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = npcm_adc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(npcm_adc_iio_channels);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
goto err_iio_register;
}
pr_info("NPCM ADC driver probed\n");
return 0;
err_iio_register:
iowrite32(reg_con & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
err_disable_clk:
clk_disable_unprepare(info->adc_clk);
return ret;
}
static int npcm_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct npcm_adc *info = iio_priv(indio_dev);
u32 regtemp;
iio_device_unregister(indio_dev);
regtemp = ioread32(info->regs + NPCM_ADCCON);
iowrite32(regtemp & ~NPCM_ADCCON_ADC_EN, info->regs + NPCM_ADCCON);
if (!IS_ERR(info->vref))
regulator_disable(info->vref);
clk_disable_unprepare(info->adc_clk);
return 0;
}
static struct platform_driver npcm_adc_driver = {
.probe = npcm_adc_probe,
.remove = npcm_adc_remove,
.driver = {
.name = "npcm_adc",
.of_match_table = npcm_adc_match,
},
};
module_platform_driver(npcm_adc_driver);
MODULE_DESCRIPTION("Nuvoton NPCM ADC Driver");
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/* TI ADS124S0X chip family driver
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*/
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/sysfs.h>
/* Commands */
#define ADS124S08_CMD_NOP 0x00
#define ADS124S08_CMD_WAKEUP 0x02
#define ADS124S08_CMD_PWRDWN 0x04
#define ADS124S08_CMD_RESET 0x06
#define ADS124S08_CMD_START 0x08
#define ADS124S08_CMD_STOP 0x0a
#define ADS124S08_CMD_SYOCAL 0x16
#define ADS124S08_CMD_SYGCAL 0x17
#define ADS124S08_CMD_SFOCAL 0x19
#define ADS124S08_CMD_RDATA 0x12
#define ADS124S08_CMD_RREG 0x20
#define ADS124S08_CMD_WREG 0x40
/* Registers */
#define ADS124S08_ID_REG 0x00
#define ADS124S08_STATUS 0x01
#define ADS124S08_INPUT_MUX 0x02
#define ADS124S08_PGA 0x03
#define ADS124S08_DATA_RATE 0x04
#define ADS124S08_REF 0x05
#define ADS124S08_IDACMAG 0x06
#define ADS124S08_IDACMUX 0x07
#define ADS124S08_VBIAS 0x08
#define ADS124S08_SYS 0x09
#define ADS124S08_OFCAL0 0x0a
#define ADS124S08_OFCAL1 0x0b
#define ADS124S08_OFCAL2 0x0c
#define ADS124S08_FSCAL0 0x0d
#define ADS124S08_FSCAL1 0x0e
#define ADS124S08_FSCAL2 0x0f
#define ADS124S08_GPIODAT 0x10
#define ADS124S08_GPIOCON 0x11
/* ADS124S0x common channels */
#define ADS124S08_AIN0 0x00
#define ADS124S08_AIN1 0x01
#define ADS124S08_AIN2 0x02
#define ADS124S08_AIN3 0x03
#define ADS124S08_AIN4 0x04
#define ADS124S08_AIN5 0x05
#define ADS124S08_AINCOM 0x0c
/* ADS124S08 only channels */
#define ADS124S08_AIN6 0x06
#define ADS124S08_AIN7 0x07
#define ADS124S08_AIN8 0x08
#define ADS124S08_AIN9 0x09
#define ADS124S08_AIN10 0x0a
#define ADS124S08_AIN11 0x0b
#define ADS124S08_MAX_CHANNELS 12
#define ADS124S08_POS_MUX_SHIFT 0x04
#define ADS124S08_INT_REF 0x09
#define ADS124S08_START_REG_MASK 0x1f
#define ADS124S08_NUM_BYTES_MASK 0x1f
#define ADS124S08_START_CONV 0x01
#define ADS124S08_STOP_CONV 0x00
enum ads124s_id {
ADS124S08_ID,
ADS124S06_ID,
};
struct ads124s_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
struct ads124s_private {
const struct ads124s_chip_info *chip_info;
struct gpio_desc *reset_gpio;
struct spi_device *spi;
struct mutex lock;
u8 data[5] ____cacheline_aligned;
};
#define ADS124S08_CHAN(index) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = 32, \
.storagebits = 32, \
}, \
}
static const struct iio_chan_spec ads124s06_channels[] = {
ADS124S08_CHAN(0),
ADS124S08_CHAN(1),
ADS124S08_CHAN(2),
ADS124S08_CHAN(3),
ADS124S08_CHAN(4),
ADS124S08_CHAN(5),
};
static const struct iio_chan_spec ads124s08_channels[] = {
ADS124S08_CHAN(0),
ADS124S08_CHAN(1),
ADS124S08_CHAN(2),
ADS124S08_CHAN(3),
ADS124S08_CHAN(4),
ADS124S08_CHAN(5),
ADS124S08_CHAN(6),
ADS124S08_CHAN(7),
ADS124S08_CHAN(8),
ADS124S08_CHAN(9),
ADS124S08_CHAN(10),
ADS124S08_CHAN(11),
};
static const struct ads124s_chip_info ads124s_chip_info_tbl[] = {
[ADS124S08_ID] = {
.channels = ads124s08_channels,
.num_channels = ARRAY_SIZE(ads124s08_channels),
},
[ADS124S06_ID] = {
.channels = ads124s06_channels,
.num_channels = ARRAY_SIZE(ads124s06_channels),
},
};
static int ads124s_write_cmd(struct iio_dev *indio_dev, u8 command)
{
struct ads124s_private *priv = iio_priv(indio_dev);
priv->data[0] = command;
return spi_write(priv->spi, &priv->data[0], 1);
}
static int ads124s_write_reg(struct iio_dev *indio_dev, u8 reg, u8 data)
{
struct ads124s_private *priv = iio_priv(indio_dev);
priv->data[0] = ADS124S08_CMD_WREG | reg;
priv->data[1] = 0x0;
priv->data[2] = data;
return spi_write(priv->spi, &priv->data[0], 3);
}
static int ads124s_reset(struct iio_dev *indio_dev)
{
struct ads124s_private *priv = iio_priv(indio_dev);
if (priv->reset_gpio) {
gpiod_set_value(priv->reset_gpio, 0);
udelay(200);
gpiod_set_value(priv->reset_gpio, 1);
} else {
return ads124s_write_cmd(indio_dev, ADS124S08_CMD_RESET);
}
return 0;
};
static int ads124s_read(struct iio_dev *indio_dev, unsigned int chan)
{
struct ads124s_private *priv = iio_priv(indio_dev);
int ret;
u32 tmp;
struct spi_transfer t[] = {
{
.tx_buf = &priv->data[0],
.len = 4,
.cs_change = 1,
}, {
.tx_buf = &priv->data[1],
.rx_buf = &priv->data[1],
.len = 4,
},
};
priv->data[0] = ADS124S08_CMD_RDATA;
memset(&priv->data[1], ADS124S08_CMD_NOP, sizeof(priv->data));
ret = spi_sync_transfer(priv->spi, t, ARRAY_SIZE(t));
if (ret < 0)
return ret;
tmp = priv->data[2] << 16 | priv->data[3] << 8 | priv->data[4];
return tmp;
}
static int ads124s_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
{
struct ads124s_private *priv = iio_priv(indio_dev);
int ret;
mutex_lock(&priv->lock);
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = ads124s_write_reg(indio_dev, ADS124S08_INPUT_MUX,
chan->channel);
if (ret) {
dev_err(&priv->spi->dev, "Set ADC CH failed\n");
goto out;
}
ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV);
if (ret) {
dev_err(&priv->spi->dev, "Start conversions failed\n");
goto out;
}
ret = ads124s_read(indio_dev, chan->channel);
if (ret < 0) {
dev_err(&priv->spi->dev, "Read ADC failed\n");
goto out;
}
*val = ret;
ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
if (ret) {
dev_err(&priv->spi->dev, "Stop conversions failed\n");
goto out;
}
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
out:
mutex_unlock(&priv->lock);
return ret;
}
static const struct iio_info ads124s_info = {
.read_raw = &ads124s_read_raw,
};
static irqreturn_t ads124s_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ads124s_private *priv = iio_priv(indio_dev);
u32 buffer[ADS124S08_MAX_CHANNELS + sizeof(s64)/sizeof(u16)];
int scan_index, j = 0;
int ret;
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = ads124s_write_reg(indio_dev, ADS124S08_INPUT_MUX,
scan_index);
if (ret)
dev_err(&priv->spi->dev, "Set ADC CH failed\n");
ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV);
if (ret)
dev_err(&priv->spi->dev, "Start ADC conversions failed\n");
buffer[j] = ads124s_read(indio_dev, scan_index);
ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
if (ret)
dev_err(&priv->spi->dev, "Stop ADC conversions failed\n");
j++;
}
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ads124s_probe(struct spi_device *spi)
{
struct ads124s_private *ads124s_priv;
struct iio_dev *indio_dev;
const struct spi_device_id *spi_id = spi_get_device_id(spi);
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*ads124s_priv));
if (indio_dev == NULL)
return -ENOMEM;
ads124s_priv = iio_priv(indio_dev);
ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(ads124s_priv->reset_gpio))
dev_info(&spi->dev, "Reset GPIO not defined\n");
ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data];
spi_set_drvdata(spi, indio_dev);
ads124s_priv->spi = spi;
indio_dev->name = spi_id->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ads124s_priv->chip_info->channels;
indio_dev->num_channels = ads124s_priv->chip_info->num_channels;
indio_dev->info = &ads124s_info;
mutex_init(&ads124s_priv->lock);
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
ads124s_trigger_handler, NULL);
if (ret) {
dev_err(&spi->dev, "iio triggered buffer setup failed\n");
return ret;
}
ads124s_reset(indio_dev);
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ads124s_id[] = {
{ "ads124s06", ADS124S06_ID },
{ "ads124s08", ADS124S08_ID },
{ }
};
MODULE_DEVICE_TABLE(spi, ads124s_id);
static const struct of_device_id ads124s_of_table[] = {
{ .compatible = "ti,ads124s06" },
{ .compatible = "ti,ads124s08" },
{ },
};
MODULE_DEVICE_TABLE(of, ads124s_of_table);
static struct spi_driver ads124s_driver = {
.driver = {
.name = "ads124s08",
.of_match_table = ads124s_of_table,
},
.probe = ads124s_probe,
.id_table = ads124s_id,
};
module_spi_driver(ads124s_driver);
MODULE_AUTHOR("Dan Murphy <dmuprhy@ti.com>");
MODULE_DESCRIPTION("TI TI_ADS12S0X ADC");
MODULE_LICENSE("GPL v2");
......@@ -1273,8 +1273,10 @@ static int xadc_probe(struct platform_device *pdev)
xadc->threshold[i] = 0xffff;
else
xadc->threshold[i] = 0;
xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
ret = xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(i),
xadc->threshold[i]);
if (ret)
goto err_free_irq;
}
/* Go to non-buffered mode */
......
......@@ -61,6 +61,27 @@ config IAQCORE
iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
sensors
config PMS7003
tristate "Plantower PMS7003 particulate matter sensor"
depends on SERIAL_DEV_BUS
help
Say Y here to build support for the Plantower PMS7003 particulate
matter sensor.
To compile this driver as a module, choose M here: the module will
be called pms7003.
config SPS30
tristate "SPS30 particulate matter sensor"
depends on I2C
select CRC8
help
Say Y here to build support for the Sensirion SPS30 particulate
matter sensor.
To compile this driver as a module, choose M here: the module will
be called sps30.
config VZ89X
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
depends on I2C
......
......@@ -9,4 +9,7 @@ obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
obj-$(CONFIG_CCS811) += ccs811.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_PMS7003) += pms7003.o
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
obj-$(CONFIG_SPS30) += sps30.o
obj-$(CONFIG_VZ89X) += vz89x.o
......@@ -70,10 +70,17 @@ static const struct acpi_device_id bme680_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
static const struct of_device_id bme680_of_i2c_match[] = {
{ .compatible = "bosch,bme680", },
{},
};
MODULE_DEVICE_TABLE(of, bme680_of_i2c_match);
static struct i2c_driver bme680_i2c_driver = {
.driver = {
.name = "bme680_i2c",
.acpi_match_table = ACPI_PTR(bme680_acpi_match),
.of_match_table = bme680_of_i2c_match,
},
.probe = bme680_i2c_probe,
.id_table = bme680_i2c_id,
......
......@@ -6,6 +6,7 @@
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
......@@ -110,10 +111,17 @@ static const struct acpi_device_id bme680_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
static const struct of_device_id bme680_of_spi_match[] = {
{ .compatible = "bosch,bme680", },
{},
};
MODULE_DEVICE_TABLE(of, bme680_of_spi_match);
static struct spi_driver bme680_spi_driver = {
.driver = {
.name = "bme680_spi",
.acpi_match_table = ACPI_PTR(bme680_acpi_match),
.of_match_table = bme680_of_spi_match,
},
.probe = bme680_spi_probe,
.id_table = bme680_spi_id,
......
// SPDX-License-Identifier: GPL-2.0
/*
* Plantower PMS7003 particulate matter sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <asm/unaligned.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/serdev.h>
#define PMS7003_DRIVER_NAME "pms7003"
#define PMS7003_MAGIC 0x424d
/* last 2 data bytes hold frame checksum */
#define PMS7003_MAX_DATA_LENGTH 28
#define PMS7003_CHECKSUM_LENGTH 2
#define PMS7003_PM10_OFFSET 10
#define PMS7003_PM2P5_OFFSET 8
#define PMS7003_PM1_OFFSET 6
#define PMS7003_TIMEOUT msecs_to_jiffies(6000)
#define PMS7003_CMD_LENGTH 7
#define PMS7003_PM_MAX 1000
#define PMS7003_PM_MIN 0
enum {
PM1,
PM2P5,
PM10,
};
enum pms7003_cmd {
CMD_WAKEUP,
CMD_ENTER_PASSIVE_MODE,
CMD_READ_PASSIVE,
CMD_SLEEP,
};
/*
* commands have following format:
*
* +------+------+-----+------+-----+-----------+-----------+
* | 0x42 | 0x4d | cmd | 0x00 | arg | cksum msb | cksum lsb |
* +------+------+-----+------+-----+-----------+-----------+
*/
static const u8 pms7003_cmd_tbl[][PMS7003_CMD_LENGTH] = {
[CMD_WAKEUP] = { 0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01, 0x74 },
[CMD_ENTER_PASSIVE_MODE] = { 0x42, 0x4d, 0xe1, 0x00, 0x00, 0x01, 0x70 },
[CMD_READ_PASSIVE] = { 0x42, 0x4d, 0xe2, 0x00, 0x00, 0x01, 0x71 },
[CMD_SLEEP] = { 0x42, 0x4d, 0xe4, 0x00, 0x00, 0x01, 0x73 },
};
struct pms7003_frame {
u8 data[PMS7003_MAX_DATA_LENGTH];
u16 expected_length;
u16 length;
};
struct pms7003_state {
struct serdev_device *serdev;
struct pms7003_frame frame;
struct completion frame_ready;
struct mutex lock; /* must be held whenever state gets touched */
};
static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
{
int ret;
ret = serdev_device_write(state->serdev, pms7003_cmd_tbl[cmd],
PMS7003_CMD_LENGTH, PMS7003_TIMEOUT);
if (ret < PMS7003_CMD_LENGTH)
return ret < 0 ? ret : -EIO;
ret = wait_for_completion_interruptible_timeout(&state->frame_ready,
PMS7003_TIMEOUT);
if (!ret)
ret = -ETIMEDOUT;
return ret < 0 ? ret : 0;
}
static u16 pms7003_get_pm(const u8 *data)
{
return clamp_val(get_unaligned_be16(data),
PMS7003_PM_MIN, PMS7003_PM_MAX);
}
static irqreturn_t pms7003_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
u16 data[3 + 1 + 4]; /* PM1, PM2P5, PM10, padding, timestamp */
int ret;
mutex_lock(&state->lock);
ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
if (ret) {
mutex_unlock(&state->lock);
goto err;
}
data[PM1] = pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
data[PM2P5] = pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
data[PM10] = pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
mutex_unlock(&state->lock);
iio_push_to_buffers_with_timestamp(indio_dev, data,
iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int pms7003_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_MASSCONCENTRATION:
mutex_lock(&state->lock);
ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
if (ret) {
mutex_unlock(&state->lock);
return ret;
}
*val = pms7003_get_pm(frame->data + chan->address);
mutex_unlock(&state->lock);
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
return -EINVAL;
}
static const struct iio_info pms7003_info = {
.read_raw = pms7003_read_raw,
};
#define PMS7003_CHAN(_index, _mod, _addr) { \
.type = IIO_MASSCONCENTRATION, \
.modified = 1, \
.channel2 = IIO_MOD_ ## _mod, \
.address = _addr, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.scan_index = _index, \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
}
static const struct iio_chan_spec pms7003_channels[] = {
PMS7003_CHAN(0, PM1, PMS7003_PM1_OFFSET),
PMS7003_CHAN(1, PM2P5, PMS7003_PM2P5_OFFSET),
PMS7003_CHAN(2, PM10, PMS7003_PM10_OFFSET),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static u16 pms7003_calc_checksum(struct pms7003_frame *frame)
{
u16 checksum = (PMS7003_MAGIC >> 8) + (u8)(PMS7003_MAGIC & 0xff) +
(frame->length >> 8) + (u8)frame->length;
int i;
for (i = 0; i < frame->length - PMS7003_CHECKSUM_LENGTH; i++)
checksum += frame->data[i];
return checksum;
}
static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
{
int offset = frame->length - PMS7003_CHECKSUM_LENGTH;
u16 checksum = get_unaligned_be16(frame->data + offset);
return checksum == pms7003_calc_checksum(frame);
}
static int pms7003_receive_buf(struct serdev_device *serdev,
const unsigned char *buf, size_t size)
{
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
int num;
if (!frame->expected_length) {
u16 magic;
/* wait for SOF and data length */
if (size < 4)
return 0;
magic = get_unaligned_be16(buf);
if (magic != PMS7003_MAGIC)
return 2;
num = get_unaligned_be16(buf + 2);
if (num <= PMS7003_MAX_DATA_LENGTH) {
frame->expected_length = num;
frame->length = 0;
}
return 4;
}
num = min(size, (size_t)(frame->expected_length - frame->length));
memcpy(frame->data + frame->length, buf, num);
frame->length += num;
if (frame->length == frame->expected_length) {
if (pms7003_frame_is_okay(frame))
complete(&state->frame_ready);
frame->expected_length = 0;
}
return num;
}
static const struct serdev_device_ops pms7003_serdev_ops = {
.receive_buf = pms7003_receive_buf,
.write_wakeup = serdev_device_write_wakeup,
};
static void pms7003_stop(void *data)
{
struct pms7003_state *state = data;
pms7003_do_cmd(state, CMD_SLEEP);
}
static const unsigned long pms7003_scan_masks[] = { 0x07, 0x00 };
static int pms7003_probe(struct serdev_device *serdev)
{
struct pms7003_state *state;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&serdev->dev, sizeof(*state));
if (!indio_dev)
return -ENOMEM;
state = iio_priv(indio_dev);
serdev_device_set_drvdata(serdev, indio_dev);
state->serdev = serdev;
indio_dev->dev.parent = &serdev->dev;
indio_dev->info = &pms7003_info;
indio_dev->name = PMS7003_DRIVER_NAME;
indio_dev->channels = pms7003_channels,
indio_dev->num_channels = ARRAY_SIZE(pms7003_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = pms7003_scan_masks;
mutex_init(&state->lock);
init_completion(&state->frame_ready);
serdev_device_set_client_ops(serdev, &pms7003_serdev_ops);
ret = devm_serdev_device_open(&serdev->dev, serdev);
if (ret)
return ret;
serdev_device_set_baudrate(serdev, 9600);
serdev_device_set_flow_control(serdev, false);
ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
if (ret)
return ret;
ret = pms7003_do_cmd(state, CMD_WAKEUP);
if (ret) {
dev_err(&serdev->dev, "failed to wakeup sensor\n");
return ret;
}
ret = pms7003_do_cmd(state, CMD_ENTER_PASSIVE_MODE);
if (ret) {
dev_err(&serdev->dev, "failed to enter passive mode\n");
return ret;
}
ret = devm_add_action_or_reset(&serdev->dev, pms7003_stop, state);
if (ret)
return ret;
ret = devm_iio_triggered_buffer_setup(&serdev->dev, indio_dev, NULL,
pms7003_trigger_handler, NULL);
if (ret)
return ret;
return devm_iio_device_register(&serdev->dev, indio_dev);
}
static const struct of_device_id pms7003_of_match[] = {
{ .compatible = "plantower,pms7003" },
{ }
};
MODULE_DEVICE_TABLE(of, pms7003_of_match);
static struct serdev_device_driver pms7003_driver = {
.driver = {
.name = PMS7003_DRIVER_NAME,
.of_match_table = pms7003_of_match,
},
.probe = pms7003_probe,
};
module_serdev_device_driver(pms7003_driver);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Plantower PMS7003 particulate matter sensor driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
This diff is collapsed.
......@@ -148,9 +148,9 @@ config AD5686_SPI
depends on SPI
select AD5686
help
Say yes here to build support for Analog Devices AD5672R, AD5676,
AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R.
Voltage Output Digital to Analog Converter.
Say yes here to build support for Analog Devices AD5672R, AD5674R,
AD5676, AD5676R, AD5679R, AD5684, AD5684R, AD5684R, AD5685R, AD5686,
AD5686R Voltage Output Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5686.
......@@ -375,6 +375,16 @@ config TI_DAC7311
If compiled as a module, it will be called ti-dac7311.
config TI_DAC7612
tristate "Texas Instruments 12-bit 2-channel DAC driver"
depends on SPI_MASTER && GPIOLIB
help
Driver for the Texas Instruments DAC7612, DAC7612U, DAC7612UB
The driver hand drive the load pin automatically, otherwise
it needs to be toggled manually.
If compiled as a module, it will be called ti-dac7612.
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
......
......@@ -41,4 +41,5 @@ obj-$(CONFIG_STM32_DAC) += stm32-dac.o
obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
obj-$(CONFIG_TI_DAC7311) += ti-dac7311.o
obj-$(CONFIG_TI_DAC7612) += ti-dac7612.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5672R, AD5676, AD5676R, AD5681R, AD5682R, AD5683, AD5683R,
* AD5684, AD5684R, AD5685R, AD5686, AD5686R
* AD5672R, AD5674R, AD5676, AD5676R, AD5679R,
* AD5681R, AD5682R, AD5683, AD5683R, AD5684,
* AD5684R, AD5685R, AD5686, AD5686R
* Digital to analog converters driver
*
* Copyright 2018 Analog Devices Inc.
......@@ -102,8 +103,10 @@ static int ad5686_spi_remove(struct spi_device *spi)
static const struct spi_device_id ad5686_spi_id[] = {
{"ad5310r", ID_AD5310R},
{"ad5672r", ID_AD5672R},
{"ad5674r", ID_AD5674R},
{"ad5676", ID_AD5676},
{"ad5676r", ID_AD5676R},
{"ad5679r", ID_AD5679R},
{"ad5681r", ID_AD5681R},
{"ad5682r", ID_AD5682R},
{"ad5683", ID_AD5683},
......
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5686R, AD5685R, AD5684R Digital to analog converters driver
*
......@@ -71,7 +71,7 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
int ret;
struct ad5686_state *st = iio_priv(indio_dev);
unsigned int val, ref_bit_msk;
u8 shift;
u8 shift, address = 0;
ret = strtobool(buf, &readin);
if (ret)
......@@ -94,6 +94,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
case AD5686_REGMAP:
shift = 0;
ref_bit_msk = 0;
/* AD5674R/AD5679R have 16 channels and 2 powerdown registers */
if (chan->channel > 0x7)
address = 0x8;
break;
case AD5693_REGMAP:
shift = 13;
......@@ -107,7 +110,8 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
if (!st->use_internal_vref)
val |= ref_bit_msk;
ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0, val);
ret = st->write(st, AD5686_CMD_POWERDOWN_DAC,
address, val >> (address * 2));
return ret ? ret : len;
}
......@@ -226,10 +230,32 @@ static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(7, 7, bits, _shift), \
}
#define DECLARE_AD5679_CHANNELS(name, bits, _shift) \
static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(0, 0, bits, _shift), \
AD5868_CHANNEL(1, 1, bits, _shift), \
AD5868_CHANNEL(2, 2, bits, _shift), \
AD5868_CHANNEL(3, 3, bits, _shift), \
AD5868_CHANNEL(4, 4, bits, _shift), \
AD5868_CHANNEL(5, 5, bits, _shift), \
AD5868_CHANNEL(6, 6, bits, _shift), \
AD5868_CHANNEL(7, 7, bits, _shift), \
AD5868_CHANNEL(8, 8, bits, _shift), \
AD5868_CHANNEL(9, 9, bits, _shift), \
AD5868_CHANNEL(10, 10, bits, _shift), \
AD5868_CHANNEL(11, 11, bits, _shift), \
AD5868_CHANNEL(12, 12, bits, _shift), \
AD5868_CHANNEL(13, 13, bits, _shift), \
AD5868_CHANNEL(14, 14, bits, _shift), \
AD5868_CHANNEL(15, 15, bits, _shift), \
}
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4);
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
DECLARE_AD5679_CHANNELS(ad5679r_channels, 16, 0);
DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4);
DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
......@@ -262,6 +288,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5674R] = {
.channels = ad5674r_channels,
.int_vref_mv = 2500,
.num_channels = 16,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5675R] = {
.channels = ad5676_channels,
.int_vref_mv = 2500,
......@@ -279,6 +311,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
.num_channels = 8,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5679R] = {
.channels = ad5679r_channels,
.int_vref_mv = 2500,
.num_channels = 16,
.regmap_type = AD5686_REGMAP,
},
[ID_AD5681R] = {
.channels = ad5691r_channels,
.int_vref_mv = 2500,
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file is part of AD5686 DAC driver
*
......@@ -54,9 +54,11 @@ enum ad5686_supported_device_ids {
ID_AD5311R,
ID_AD5671R,
ID_AD5672R,
ID_AD5674R,
ID_AD5675R,
ID_AD5676,
ID_AD5676R,
ID_AD5679R,
ID_AD5681R,
ID_AD5682R,
ID_AD5683,
......
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R,
* AD5694, AD5694R, AD5695R, AD5696, AD5696R
......
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5758 Digital to analog converters driver
*
......
This diff is collapsed.
......@@ -943,11 +943,14 @@ static int ad9523_setup(struct iio_dev *indio_dev)
}
}
for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN)
ad9523_write(indio_dev,
for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN) {
ret = ad9523_write(indio_dev,
AD9523_CHANNEL_CLOCK_DIST(i),
AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) |
AD9523_CLK_DIST_PWR_DOWN_EN);
if (ret < 0)
return ret;
}
ret = ad9523_write(indio_dev, AD9523_POWER_DOWN_CTRL, 0);
if (ret < 0)
......
......@@ -2,9 +2,20 @@
#ifndef BMI160_H_
#define BMI160_H_
#include <linux/iio/iio.h>
struct bmi160_data {
struct regmap *regmap;
struct iio_trigger *trig;
};
extern const struct regmap_config bmi160_regmap_config;
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
int bmi160_enable_irq(struct regmap *regmap, bool enable);
int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type);
#endif /* BMI160_H_ */
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU, I2C bits
*
* Copyright (c) 2016, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address is:
* - 0x68 if SDO is pulled to GND
* - 0x69 if SDO is pulled to VDDIO
......
// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU, SPI bits
*
* Copyright (c) 2016, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*/
#include <linux/acpi.h>
#include <linux/module.h>
......
......@@ -13,8 +13,8 @@ config INV_MPU6050_I2C
select INV_MPU6050_IIO
select REGMAP_I2C
help
This driver supports the Invensense MPU6050/6500/9150 and ICM20608
motion tracking devices over I2C.
This driver supports the Invensense MPU6050/6500/9150 and
ICM20608/20602 motion tracking devices over I2C.
This driver can be built as a module. The module will be called
inv-mpu6050-i2c.
......@@ -24,7 +24,7 @@ config INV_MPU6050_SPI
select INV_MPU6050_IIO
select REGMAP_SPI
help
This driver supports the Invensense MPU6050/6500/9150 and ICM20608
motion tracking devices over SPI.
This driver supports the Invensense MPU6050/6500/9150 and
ICM20608/20602 motion tracking devices over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.
......@@ -38,6 +38,29 @@ static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724};
*/
static const int accel_scale[] = {598, 1196, 2392, 4785};
static const struct inv_mpu6050_reg_map reg_set_icm20602 = {
.sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
.lpf = INV_MPU6050_REG_CONFIG,
.accel_lpf = INV_MPU6500_REG_ACCEL_CONFIG_2,
.user_ctrl = INV_MPU6050_REG_USER_CTRL,
.fifo_en = INV_MPU6050_REG_FIFO_EN,
.gyro_config = INV_MPU6050_REG_GYRO_CONFIG,
.accl_config = INV_MPU6050_REG_ACCEL_CONFIG,
.fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H,
.fifo_r_w = INV_MPU6050_REG_FIFO_R_W,
.raw_gyro = INV_MPU6050_REG_RAW_GYRO,
.raw_accl = INV_MPU6050_REG_RAW_ACCEL,
.temperature = INV_MPU6050_REG_TEMPERATURE,
.int_enable = INV_MPU6050_REG_INT_ENABLE,
.int_status = INV_MPU6050_REG_INT_STATUS,
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
.accl_offset = INV_MPU6500_REG_ACCEL_OFFSET,
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
.i2c_if = INV_ICM20602_REG_I2C_IF,
};
static const struct inv_mpu6050_reg_map reg_set_6500 = {
.sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
.lpf = INV_MPU6050_REG_CONFIG,
......@@ -58,6 +81,7 @@ static const struct inv_mpu6050_reg_map reg_set_6500 = {
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
.accl_offset = INV_MPU6500_REG_ACCEL_OFFSET,
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
.i2c_if = 0,
};
static const struct inv_mpu6050_reg_map reg_set_6050 = {
......@@ -78,6 +102,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
.accl_offset = INV_MPU6050_REG_ACCEL_OFFSET,
.gyro_offset = INV_MPU6050_REG_GYRO_OFFSET,
.i2c_if = 0,
};
static const struct inv_mpu6050_chip_config chip_config_6050 = {
......@@ -140,6 +165,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
{
.whoami = INV_ICM20602_WHOAMI_VALUE,
.name = "ICM20602",
.reg = &reg_set_icm20602,
.config = &chip_config_6050,
},
};
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* drivers/staging/android/uapi/ion.h
*
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment