Second set of IIO new device support, features and cleanups.

There are also a couple of fixes that can wait for the coming merge
 window.
 
 Core new features
 
 * Support for phase channels (used in time of flight sensors amongst
   other things)
 * Support for deep UV light channel modifier.
 
 New Device Support
 
 * AD4758 DAC
   - New driver and dt bindings.
 * adxl345
   - Support the adxl375 +-200g part which is register compatible.
 * isl29501 Time of flight sensor.
   - New driver
 * meson-saradc
   - Support the Meson8m2 Socs - right now this is just an ID, but there will
     be additional difference in future.
 * mpu6050
   - New ID for 6515 variant.
 * si1133 UV sensor.
   - New driver
 * Spreadtrum SC27xx PMIC ADC
   - New driver and dt bindings.
 
 Features
 
 * adxl345
   - Add calibration offset readback and writing.
   - Add sampling frequency control.
 
 Fixes and Cleanups
 
 * ad5933
   - Use a macro for the channel definition to reduce duplication.
 * ad9523
   - Replace use of core mlock with a local lock. Part of ongoing efforts
     to avoid confusing the purpose of mlock which is only about iio core
     state changes.
   - Fix displayed phase which was out by a factor of 10.
 * adxl345
   - Add a link to the datasheet.
   - Rework the use of the address field in the chan_spec structures to
     allow addition of more per channel information.
 * adis imu
   - Mark switch fall throughs.
 * at91-sama5d2
   - Fix some casting on big endian systems.
 * bmp280
   - Drop some DT elements that aren't used and should mostly be done from
     userspace rather than in DT.
 * hx711
   - add clock-frequency dt binding and resulting delay to deal with capacitance
     issue on some boards.
   - fix a spurious unit-address in the example.
 * ina2xx
   - Avoid a possible kthread_stop with a stale task_struct.
 * ltc2632
   - Remove some unused local variables (assigned but value never used).
 * max1363
   - Use device_get_match_data to remove some boilerplate.
 * mma8452
   - Mark switch fall throughs.
 * sca3000
   - Fix a missing return in a switch statement (a bad fallthrough
     previously!)
 * sigma-delta-modulator
   - Drop incorrect unit address from the DT example.
 * st_accel
   - Use device_get_match_data to drop some boiler plate.
   - Move to probe_new for i2c driver as second parameter not used.
 * st_sensors library
   - Use a strlcpy (safe in this case).
 * st_lsm6dsx
   - Add some error logging.
 * ti-ads7950
   - SPDX
   - Allow simultaneous buffered and polled reads. Needed on a Lego Mindstorms
     EV3 where some channels are used for power supply monitoring at a very low
     rate.
 * ti-dac5571
   - Remove an unused variable.
 * xadc
   - Drop some dead code.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAltXZAkRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FohYZQ//VAjpDBYjLzYTvTJy5bDt61fbh8KabhBf
 oxLIpwYrCeleLnpbrY7nU8shdIL7Vm755jtsHbTtQPCKSQ0RGnhLLDoqoWcmn70J
 rF9iVaSv+S2lZO+9+hv2eeqyX+kSM+74fkWRuLmDbaSZWYO4Jt9zFER1zizmPypY
 DnxLcViw1kwOLbiZKwmcaK0MqlWHRPhEEcNVKy7VGZHznbylujh8evkzzQNVWOol
 QrR2NG7V8BcLTflmsYCErQDvgciGjscnVZUAyY3yNLIpceGCSHZfUsE8ld6iPrS+
 aPeuiIxDhHAKyoOTQwsGi9ex7KEOUOkoDHhKdR3Jr74mtfcPF5B+TxgXU0p5UZ9g
 GummuvSX0izYjUZ9P4keVgu3W4bvmR9Kd8oJUHNByWI1iecoXP9bQf33tEyb26R6
 G1zvGSDXPNK1V7OEaGvzGkgxOY0ZAIWLRX/+wasErdJnt3lmOV9+cCSkJAFSNrk3
 jQ922q2ZWLfYAL6nNIAx2dIiJirxTQ2JIq/bys2BHiYvkuvqNcKoBIDAGlQ4xBKm
 /c5z9Dm/DxQpdlKFQugHmc5awLEZxpq2LCTBLlgM8z6+uRWXui+slPfIrfX5RWun
 BHaLmPNm6tKQLadjwWCoxXYjKqgK0wm35Yq5d5He7d45d3QWKvtUgZAj33pcIgTE
 wKmwF5oaLiU=
 =T+hS
 -----END PGP SIGNATURE-----

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

Jonathan writes:

Second set of IIO new device support, features and cleanups.

There are also a couple of fixes that can wait for the coming merge
window.

Core new features

* Support for phase channels (used in time of flight sensors amongst
  other things)
* Support for deep UV light channel modifier.

New Device Support

* AD4758 DAC
  - New driver and dt bindings.
* adxl345
  - Support the adxl375 +-200g part which is register compatible.
* isl29501 Time of flight sensor.
  - New driver
* meson-saradc
  - Support the Meson8m2 Socs - right now this is just an ID, but there will
    be additional difference in future.
* mpu6050
  - New ID for 6515 variant.
* si1133 UV sensor.
  - New driver
* Spreadtrum SC27xx PMIC ADC
  - New driver and dt bindings.

Features

* adxl345
  - Add calibration offset readback and writing.
  - Add sampling frequency control.

Fixes and Cleanups

* ad5933
  - Use a macro for the channel definition to reduce duplication.
* ad9523
  - Replace use of core mlock with a local lock. Part of ongoing efforts
    to avoid confusing the purpose of mlock which is only about iio core
    state changes.
  - Fix displayed phase which was out by a factor of 10.
* adxl345
  - Add a link to the datasheet.
  - Rework the use of the address field in the chan_spec structures to
    allow addition of more per channel information.
* adis imu
  - Mark switch fall throughs.
* at91-sama5d2
  - Fix some casting on big endian systems.
* bmp280
  - Drop some DT elements that aren't used and should mostly be done from
    userspace rather than in DT.
* hx711
  - add clock-frequency dt binding and resulting delay to deal with capacitance
    issue on some boards.
  - fix a spurious unit-address in the example.
* ina2xx
  - Avoid a possible kthread_stop with a stale task_struct.
* ltc2632
  - Remove some unused local variables (assigned but value never used).
* max1363
  - Use device_get_match_data to remove some boilerplate.
* mma8452
  - Mark switch fall throughs.
* sca3000
  - Fix a missing return in a switch statement (a bad fallthrough
    previously!)
* sigma-delta-modulator
  - Drop incorrect unit address from the DT example.
* st_accel
  - Use device_get_match_data to drop some boiler plate.
  - Move to probe_new for i2c driver as second parameter not used.
* st_sensors library
  - Use a strlcpy (safe in this case).
* st_lsm6dsx
  - Add some error logging.
* ti-ads7950
  - SPDX
  - Allow simultaneous buffered and polled reads. Needed on a Lego Mindstorms
    EV3 where some channels are used for power supply monitoring at a very low
    rate.
* ti-dac5571
  - Remove an unused variable.
* xadc
  - Drop some dead code.
This commit is contained in:
Greg Kroah-Hartman 2018-07-25 10:12:07 +02:00
commit 3ceefa3ffd
54 changed files with 4139 additions and 175 deletions

View File

@ -1307,13 +1307,16 @@ What: /sys/.../iio:deviceX/in_intensityY_raw
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
What: /sys/.../iio:deviceX/in_intensityY_both_raw
What: /sys/.../iio:deviceX/in_intensityY_uv_raw
What: /sys/.../iio:deviceX/in_intensityY_duv_raw
KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org
Description:
Unit-less light intensity. Modifiers both and ir indicate
that measurements contain visible and infrared light
components or just infrared light, respectively. Modifier uv indicates
that measurements contain ultraviolet light components.
components or just infrared light, respectively. Modifier
uv indicates that measurements contain ultraviolet light
components. Modifier duv indicates that measurements
contain deep ultraviolet light components.
What: /sys/.../iio:deviceX/in_uvindex_input
KernelVersion: 4.6
@ -1675,3 +1678,10 @@ KernelVersion: 4.12
Contact: linux-iio@vger.kernel.org
Description:
Raw counter device counters direction for channel Y.
What: /sys/bus/iio/devices/iio:deviceX/in_phaseY_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled) phase difference reading from channel Y
that can be processed to radians.

View File

@ -0,0 +1,47 @@
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_agc_gain
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_agc_gain_bias
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
This sensor has an automatic gain control (agc) loop
which sets the analog signal levels at an optimum
level by controlling programmable gain amplifiers. The
criteria for optimal gain is determined by the sensor.
Return the actual gain value as an integer in [0; 65536]
range when read from.
The agc gain read when measuring crosstalk shall be
written into in_proximity0_agc_gain_bias.
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_temp_a
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_temp_b
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_light_a
What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calib_phase_light_b
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
The sensor is able to perform correction of distance
measurements due to changing temperature and ambient
light conditions. It can be programmed to correct for
a second order error polynomial.
Phase data has to be collected when temperature and
ambient light are modulated independently.
Then a least squares curve fit to a second order
polynomial has to be generated from the data. The
resultant curves have the form ax^2 + bx + c.
From those two curves, a and b coefficients shall be
stored in in_proximity0_calib_phase_temp_a and
in_proximity0_calib_phase_temp_b for temperature and
in in_proximity0_calib_phase_light_a and
in_proximity0_calib_phase_light_b for ambient light.
Those values must be integer in [0; 8355840] range.
Finally, the c constant is set by the sensor
internally.
The value stored in sensor is displayed when read from.

View File

@ -0,0 +1,22 @@
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_small_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Unit-less infrared intensity. The intensity is measured from 1
dark photodiode. "small" indicate the surface area capturing
infrared.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_ir_large_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Unit-less infrared intensity. The intensity is measured from 4
dark photodiodes. "large" indicate the surface area capturing
infrared.
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_large_raw
KernelVersion: 4.18
Contact: linux-iio@vger.kernel.org
Description:
Unit-less light intensity with more diodes.

View File

@ -1,9 +1,12 @@
Analog Devices ADXL345 3-Axis, +/-(2g/4g/8g/16g) Digital Accelerometer
Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers
http://www.analog.com/en/products/mems/accelerometers/adxl345.html
http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html
Required properties:
- compatible : should be "adi,adxl345"
- compatible : should be one of
"adi,adxl345"
"adi,adxl375"
- reg : the I2C address or SPI chip select number of the sensor
Required properties for SPI bus usage:

View File

@ -4,6 +4,7 @@ Required properties:
- compatible: depending on the SoC this should be one of:
- "amlogic,meson8-saradc" for Meson8
- "amlogic,meson8b-saradc" for Meson8b
- "amlogic,meson8m2-saradc" for Meson8m2
- "amlogic,meson-gxbb-saradc" for GXBB
- "amlogic,meson-gxl-saradc" for GXL
- "amlogic,meson-gxm-saradc" for GXM

View File

@ -8,11 +8,17 @@ Required properties:
See Documentation/devicetree/bindings/gpio/gpio.txt
- avdd-supply: Definition of the regulator used as analog supply
Optional properties:
- clock-frequency: Frequency of PD_SCK in Hz
Minimum value allowed is 10 kHz because of maximum
high time of 50 microseconds.
Example:
weight@0 {
weight {
compatible = "avia,hx711";
sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
avdd-suppy = <&avdd>;
clock-frequency = <100000>;
};

View File

@ -7,7 +7,7 @@ Required properties:
Example node:
ads1202: adc@0 {
ads1202: adc {
compatible = "sd-modulator";
#io-channel-cells = <0>;
};

View File

@ -0,0 +1,36 @@
Spreadtrum SC27XX series PMICs ADC binding
Required properties:
- compatible: Should be one of the following.
"sprd,sc2720-adc"
"sprd,sc2721-adc"
"sprd,sc2723-adc"
"sprd,sc2730-adc"
"sprd,sc2731-adc"
- reg: The address offset of ADC controller.
- interrupt-parent: The interrupt controller.
- interrupts: The interrupt number for the ADC device.
- #io-channel-cells: Number of cells in an IIO specifier.
- hwlocks: Reference to a phandle of a hwlock provider node.
Example:
sc2731_pmic: pmic@0 {
compatible = "sprd,sc2731";
reg = <0>;
spi-max-frequency = <26000000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <0>;
pmic_adc: adc@480 {
compatible = "sprd,sc2731-adc";
reg = <0x480>;
interrupt-parent = <&sc2731_pmic>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
#io-channel-cells = <1>;
hwlocks = <&hwlock 4>;
};
};

View File

@ -0,0 +1,78 @@
Analog Devices AD5758 DAC device driver
Required properties for the AD5758:
- compatible: Must be "adi,ad5758"
- reg: SPI chip select number for the device
- spi-max-frequency: Max SPI frequency to use (< 50000000)
- spi-cpha: is the only mode that is supported
Required properties:
- adi,dc-dc-mode: Mode of operation of the dc-to-dc converter
Dynamic Power Control (DPC)
In this mode, the AD5758 circuitry senses the output
voltage and dynamically regulates the supply voltage,
VDPC+, to meet compliance requirements plus an optimized
headroom voltage for the output buffer.
Programmable Power Control (PPC)
In this mode, the VDPC+ voltage is user-programmable to
a fixed level that needs to accommodate the maximum output
load required.
The output of the DAC core is either converted to a
current or voltage output at the VIOUT pin. Only one mode
can be enabled at any one time.
The following values are currently supported:
* 1: DPC current mode
* 2: DPC voltage mode
* 3: PPC current mode
Depending on the selected output mode (voltage or current) one of the
two properties must
be present:
- adi,range-microvolt: Voltage output range
The array of voltage output ranges must contain two fields:
* <0 5000000>: 0 V to 5 V voltage range
* <0 10000000>: 0 V to 10 V voltage range
* <(-5000000) 5000000>: ±5 V voltage range
* <(-10000000) 10000000>: ±10 V voltage range
- adi,range-microamp: Current output range
The array of current output ranges must contain two fields:
* <0 20000>: 0 mA to 20 mA current range
* <0 24000>: 0 mA to 24 mA current range
* <4 24000>: 4 mA to 20 mA current range
* <(-20000) 20000>: ±20 mA current range
* <(-24000) 24000>: ±24 mA current range
* <(-1000) 22000>: 1 mA to +22 mA current range
Optional properties:
- adi,dc-dc-ilim-microamp: The dc-to-dc converter current limit
The following values are currently supported [uA]:
* 150000
* 200000
* 250000
* 300000
* 350000
* 400000
- adi,slew-time-us: The time it takes for the output to reach the
full scale [uS]
The supported range is between 133us up to 1023984375us
AD5758 Example:
dac@0 {
compatible = "adi,ad5758";
reg = <0>;
spi-max-frequency = <1000000>;
spi-cpha;
adi,dc-dc-mode = <2>;
adi,range-microvolt = <0 10000000>;
adi,dc-dc-ilim-microamp = <200000>;
adi,slew-time-us = <125000>;
};

View File

@ -6,6 +6,7 @@ Required properties:
- compatible : should be one of
"invensense,mpu6050"
"invensense,mpu6500"
"invensense,mpu6515"
"invensense,mpu9150"
"invensense,mpu9250"
"invensense,mpu9255"

View File

@ -0,0 +1,13 @@
* ISL29501 Time-of-flight sensor.
Required properties:
- compatible : should be "renesas,isl29501"
- reg : the I2C address of the sensor
Example:
isl29501@57 {
compatible = "renesas,isl29501";
reg = <0x57>;
};

View File

@ -8,10 +8,6 @@ Required properties:
"bosch,bme280"
Optional properties:
- chip-id: configurable chip id for non-default chip revisions
- temp-measurement-period: temperature measurement period (milliseconds)
- default-oversampling: default oversampling value to be used at startup,
value range is 0-3 with rising sensitivity.
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for IRQ
- reset-gpios: a GPIO line handling reset of the sensor: as the line is
@ -24,9 +20,6 @@ Example:
pressure@77 {
compatible = "bosch,bmp085";
reg = <0x77>;
chip-id = <10>;
temp-measurement-period = <100>;
default-oversampling = <2>;
interrupt-parent = <&gpio0>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>;

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 816 B

View File

@ -796,6 +796,14 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch>
S: Supported
F: drivers/macintosh/ams/
ANALOG DEVICES INC AD5758 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/dac/ad5758.c
F: Documentation/devicetree/bindings/iio/dac/ad5758.txt
ANALOG DEVICES INC AD5686 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-pm@vger.kernel.org

View File

@ -40,7 +40,7 @@ config ADXL345_I2C
select REGMAP_I2C
help
Say Y here if you want to build support for the Analog Devices
ADXL345 3-axis digital accelerometer.
ADXL345 or ADXL375 3-axis digital accelerometer.
To compile this driver as a module, choose M here: the module
will be called adxl345_i2c and you will also get adxl345_core
@ -54,7 +54,7 @@ config ADXL345_SPI
select REGMAP_SPI
help
Say Y here if you want to build support for the Analog Devices
ADXL345 3-axis digital accelerometer.
ADXL345 or ADXL375 3-axis digital accelerometer.
To compile this driver as a module, choose M here: the module
will be called adxl345_spi and you will also get adxl345_core

View File

@ -11,8 +11,13 @@
#ifndef _ADXL345_H_
#define _ADXL345_H_
enum adxl345_device_type {
ADXL345,
ADXL375,
};
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
const char *name);
enum adxl345_device_type type, const char *name);
int adxl345_core_remove(struct device *dev);
#endif /* _ADXL345_H_ */

View File

@ -6,21 +6,35 @@
* 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.
*
* Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include "adxl345.h"
#define ADXL345_REG_DEVID 0x00
#define ADXL345_REG_OFSX 0x1e
#define ADXL345_REG_OFSY 0x1f
#define ADXL345_REG_OFSZ 0x20
#define ADXL345_REG_OFS_AXIS(index) (ADXL345_REG_OFSX + (index))
#define ADXL345_REG_BW_RATE 0x2C
#define ADXL345_REG_POWER_CTL 0x2D
#define ADXL345_REG_DATA_FORMAT 0x31
#define ADXL345_REG_DATAX0 0x32
#define ADXL345_REG_DATAY0 0x34
#define ADXL345_REG_DATAZ0 0x36
#define ADXL345_REG_DATA_AXIS(index) \
(ADXL345_REG_DATAX0 + (index) * sizeof(__le16))
#define ADXL345_BW_RATE GENMASK(3, 0)
#define ADXL345_BASE_RATE_NANO_HZ 97656250LL
#define NHZ_PER_HZ 1000000000LL
#define ADXL345_POWER_CTL_MEASURE BIT(3)
#define ADXL345_POWER_CTL_STANDBY 0x00
@ -42,24 +56,33 @@
*/
static const int adxl345_uscale = 38300;
/*
* The Datasheet lists a resolution of Resolution is ~49 mg per LSB. That's
* ~480mm/s**2 per LSB.
*/
static const int adxl375_uscale = 480000;
struct adxl345_data {
struct regmap *regmap;
u8 data_range;
enum adxl345_device_type type;
};
#define ADXL345_CHANNEL(reg, axis) { \
#define ADXL345_CHANNEL(index, axis) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.address = reg, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec adxl345_channels[] = {
ADXL345_CHANNEL(ADXL345_REG_DATAX0, X),
ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y),
ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z),
ADXL345_CHANNEL(0, X),
ADXL345_CHANNEL(1, Y),
ADXL345_CHANNEL(2, Z),
};
static int adxl345_read_raw(struct iio_dev *indio_dev,
@ -67,7 +90,9 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
__le16 regval;
__le16 accel;
long long samp_freq_nhz;
unsigned int regval;
int ret;
switch (mask) {
@ -77,29 +102,117 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
* ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
* and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
*/
ret = regmap_bulk_read(data->regmap, chan->address, &regval,
sizeof(regval));
ret = regmap_bulk_read(data->regmap,
ADXL345_REG_DATA_AXIS(chan->address),
&accel, sizeof(accel));
if (ret < 0)
return ret;
*val = sign_extend32(le16_to_cpu(regval), 12);
*val = sign_extend32(le16_to_cpu(accel), 12);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = adxl345_uscale;
switch (data->type) {
case ADXL345:
*val2 = adxl345_uscale;
break;
case ADXL375:
*val2 = adxl375_uscale;
break;
}
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
ret = regmap_read(data->regmap,
ADXL345_REG_OFS_AXIS(chan->address), &regval);
if (ret < 0)
return ret;
/*
* 8-bit resolution at +/- 2g, that is 4x accel data scale
* factor
*/
*val = sign_extend32(regval, 7) * 4;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, &regval);
if (ret < 0)
return ret;
samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
(regval & ADXL345_BW_RATE);
*val = div_s64_rem(samp_freq_nhz, NHZ_PER_HZ, val2);
return IIO_VAL_INT_PLUS_NANO;
}
return -EINVAL;
}
static int adxl345_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
s64 n;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
/*
* 8-bit resolution at +/- 2g, that is 4x accel data scale
* factor
*/
return regmap_write(data->regmap,
ADXL345_REG_OFS_AXIS(chan->address),
val / 4);
case IIO_CHAN_INFO_SAMP_FREQ:
n = div_s64(val * NHZ_PER_HZ + val2, ADXL345_BASE_RATE_NANO_HZ);
return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,
ADXL345_BW_RATE,
clamp_val(ilog2(n), 0,
ADXL345_BW_RATE));
}
return -EINVAL;
}
static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
);
static struct attribute *adxl345_attrs[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group adxl345_attrs_group = {
.attrs = adxl345_attrs,
};
static const struct iio_info adxl345_info = {
.attrs = &adxl345_attrs_group,
.read_raw = adxl345_read_raw,
.write_raw = adxl345_write_raw,
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
};
int adxl345_core_probe(struct device *dev, struct regmap *regmap,
const char *name)
enum adxl345_device_type type, const char *name)
{
struct adxl345_data *data;
struct iio_dev *indio_dev;
@ -125,6 +238,7 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
data->type = type;
/* Enable full-resolution mode */
data->data_range = ADXL345_DATA_FORMAT_FULL_RES;

View File

@ -34,7 +34,8 @@ static int adxl345_i2c_probe(struct i2c_client *client,
return PTR_ERR(regmap);
}
return adxl345_core_probe(&client->dev, regmap, id ? id->name : NULL);
return adxl345_core_probe(&client->dev, regmap, id->driver_data,
id ? id->name : NULL);
}
static int adxl345_i2c_remove(struct i2c_client *client)
@ -43,7 +44,8 @@ static int adxl345_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id adxl345_i2c_id[] = {
{ "adxl345", 0 },
{ "adxl345", ADXL345 },
{ "adxl375", ADXL375 },
{ }
};
@ -51,6 +53,7 @@ MODULE_DEVICE_TABLE(i2c, adxl345_i2c_id);
static const struct of_device_id adxl345_of_match[] = {
{ .compatible = "adi,adxl345" },
{ .compatible = "adi,adxl375" },
{ },
};

View File

@ -42,7 +42,7 @@ static int adxl345_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
}
return adxl345_core_probe(&spi->dev, regmap, id->name);
return adxl345_core_probe(&spi->dev, regmap, id->driver_data, id->name);
}
static int adxl345_spi_remove(struct spi_device *spi)
@ -51,7 +51,8 @@ static int adxl345_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id adxl345_spi_id[] = {
{ "adxl345", 0 },
{ "adxl345", ADXL345 },
{ "adxl375", ADXL375 },
{ }
};
@ -59,6 +60,7 @@ MODULE_DEVICE_TABLE(spi, adxl345_spi_id);
static const struct of_device_id adxl345_of_match[] = {
{ .compatible = "adi,adxl345" },
{ .compatible = "adi,adxl375" },
{ },
};

View File

@ -1547,6 +1547,7 @@ static int mma8452_probe(struct i2c_client *client,
case FXLS8471_DEVICE_ID:
if (ret == data->chip_info->chip_id)
break;
/* else: fall through */
default:
return -ENODEV;
}

View File

@ -797,6 +797,7 @@ static int sca3000_write_raw(struct iio_dev *indio_dev,
mutex_lock(&st->lock);
ret = sca3000_write_3db_freq(st, val);
mutex_unlock(&st->lock);
return ret;
default:
return -EINVAL;
}

View File

@ -14,8 +14,8 @@
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/property.h>
#include <linux/iio/common/st_sensors.h>
#include <linux/iio/common/st_sensors_i2c.h>
#include "st_accel.h"
@ -107,8 +107,8 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id st_accel_acpi_match[] = {
{"SMO8840", LNG2DM},
{"SMO8A90", LNG2DM},
{"SMO8840", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
{"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
{ },
};
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
@ -117,33 +117,33 @@ MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
#endif
static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DLH_ACCEL_DEV_NAME, LSM303DLH },
{ LSM303DLHC_ACCEL_DEV_NAME, LSM303DLHC },
{ LIS3DH_ACCEL_DEV_NAME, LIS3DH },
{ LSM330D_ACCEL_DEV_NAME, LSM330D },
{ LSM330DL_ACCEL_DEV_NAME, LSM330DL },
{ LSM330DLC_ACCEL_DEV_NAME, LSM330DLC },
{ LIS331DLH_ACCEL_DEV_NAME, LIS331DLH },
{ LSM303DL_ACCEL_DEV_NAME, LSM303DL },
{ LSM303DLM_ACCEL_DEV_NAME, LSM303DLM },
{ LSM330_ACCEL_DEV_NAME, LSM330 },
{ LSM303AGR_ACCEL_DEV_NAME, LSM303AGR },
{ LIS2DH12_ACCEL_DEV_NAME, LIS2DH12 },
{ LIS3L02DQ_ACCEL_DEV_NAME, LIS3L02DQ },
{ LNG2DM_ACCEL_DEV_NAME, LNG2DM },
{ H3LIS331DL_ACCEL_DEV_NAME, H3LIS331DL },
{ LIS331DL_ACCEL_DEV_NAME, LIS331DL },
{ LIS3LV02DL_ACCEL_DEV_NAME, LIS3LV02DL },
{ LIS2DW12_ACCEL_DEV_NAME, LIS2DW12 },
{ LSM303DLH_ACCEL_DEV_NAME },
{ LSM303DLHC_ACCEL_DEV_NAME },
{ LIS3DH_ACCEL_DEV_NAME },
{ LSM330D_ACCEL_DEV_NAME },
{ LSM330DL_ACCEL_DEV_NAME },
{ LSM330DLC_ACCEL_DEV_NAME },
{ LIS331DLH_ACCEL_DEV_NAME },
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{ LIS2DH12_ACCEL_DEV_NAME },
{ LIS3L02DQ_ACCEL_DEV_NAME },
{ LNG2DM_ACCEL_DEV_NAME },
{ H3LIS331DL_ACCEL_DEV_NAME },
{ LIS331DL_ACCEL_DEV_NAME },
{ LIS3LV02DL_ACCEL_DEV_NAME },
{ LIS2DW12_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
static int st_accel_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int st_accel_i2c_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
struct st_sensor_data *adata;
const char *match;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
@ -152,19 +152,9 @@ static int st_accel_i2c_probe(struct i2c_client *client,
adata = iio_priv(indio_dev);
if (client->dev.of_node) {
st_sensors_of_name_probe(&client->dev, st_accel_of_match,
client->name, sizeof(client->name));
} else if (ACPI_HANDLE(&client->dev)) {
ret = st_sensors_match_acpi_device(&client->dev);
if ((ret < 0) || (ret >= ST_ACCEL_MAX))
return -ENODEV;
strlcpy(client->name, st_accel_id_table[ret].name,
sizeof(client->name));
} else if (!id)
return -ENODEV;
match = device_get_match_data(&client->dev);
if (match)
strlcpy(client->name, match, sizeof(client->name));
st_sensors_i2c_configure(indio_dev, client, adata);
@ -188,7 +178,7 @@ static struct i2c_driver st_accel_driver = {
.of_match_table = of_match_ptr(st_accel_of_match),
.acpi_match_table = ACPI_PTR(st_accel_acpi_match),
},
.probe = st_accel_i2c_probe,
.probe_new = st_accel_i2c_probe,
.remove = st_accel_i2c_remove,
.id_table = st_accel_id_table,
};

View File

@ -620,6 +620,16 @@ config ROCKCHIP_SARADC
To compile this driver as a module, choose M here: the
module will be called rockchip_saradc.
config SC27XX_ADC
tristate "Spreadtrum SC27xx series PMICs ADC"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
help
Say yes here to build support for the integrated ADC inside the
Spreadtrum SC27xx series PMICs.
This driver can also be built as a module. If so, the module
will be called sc27xx_adc.
config SPEAR_ADC
tristate "ST SPEAr ADC"
depends on PLAT_SPEAR || COMPILE_TEST

View File

@ -59,6 +59,7 @@ obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
obj-$(CONFIG_STX104) += stx104.o
obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o

View File

@ -1296,6 +1296,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
{
struct at91_adc_state *st = iio_priv(indio_dev);
u32 cor = 0;
u16 tmp_val;
int ret;
/*
@ -1309,7 +1310,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
mutex_lock(&st->lock);
ret = at91_adc_read_position(st, chan->channel,
(u16 *)val);
&tmp_val);
*val = tmp_val;
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
@ -1322,7 +1324,8 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
mutex_lock(&st->lock);
ret = at91_adc_read_pressure(st, chan->channel,
(u16 *)val);
&tmp_val);
*val = tmp_val;
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);

View File

@ -97,6 +97,14 @@ struct hx711_data {
* 2x32-bit channel + 64-bit timestamp
*/
u32 buffer[4];
/*
* delay after a rising edge on SCK until the data is ready DOUT
* this is dependent on the hx711 where the datasheet tells a
* maximum value of 100 ns
* but also on potential parasitic capacities on the wiring
*/
u32 data_ready_delay_ns;
u32 clock_frequency;
};
static int hx711_cycle(struct hx711_data *hx711_data)
@ -110,6 +118,14 @@ static int hx711_cycle(struct hx711_data *hx711_data)
*/
preempt_disable();
gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
/*
* wait until DOUT is ready
* it turned out that parasitic capacities are extending the time
* until DOUT has reached it's value
*/
ndelay(hx711_data->data_ready_delay_ns);
val = gpiod_get_value(hx711_data->gpiod_dout);
/*
* here we are not waiting for 0.2 us as suggested by the datasheet,
@ -120,6 +136,12 @@ static int hx711_cycle(struct hx711_data *hx711_data)
gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
preempt_enable();
/*
* make it a square wave for addressing cases with capacitance on
* PC_SCK
*/
ndelay(hx711_data->data_ready_delay_ns);
return val;
}
@ -458,6 +480,7 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
static int hx711_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct hx711_data *hx711_data;
struct iio_dev *indio_dev;
int ret;
@ -530,6 +553,22 @@ static int hx711_probe(struct platform_device *pdev)
hx711_data->gain_set = 128;
hx711_data->gain_chan_a = 128;
hx711_data->clock_frequency = 400000;
ret = of_property_read_u32(np, "clock-frequency",
&hx711_data->clock_frequency);
/*
* datasheet says the high level of PD_SCK has a maximum duration
* of 50 microseconds
*/
if (hx711_data->clock_frequency < 20000) {
dev_warn(dev, "clock-frequency too low - assuming 400 kHz\n");
hx711_data->clock_frequency = 400000;
}
hx711_data->data_ready_delay_ns =
1000000000 / hx711_data->clock_frequency;
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = "hx711";

View File

@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/sched/task.h>
#include <linux/util_macros.h>
#include <linux/platform_data/ina2xx.h>
@ -826,6 +827,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
{
struct ina2xx_chip_info *chip = iio_priv(indio_dev);
unsigned int sampling_us = SAMPLING_PERIOD(chip);
struct task_struct *task;
dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n",
(unsigned int)(*indio_dev->active_scan_mask),
@ -835,11 +837,17 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
chip->allow_async_readout);
chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
"%s:%d-%uus", indio_dev->name, indio_dev->id,
sampling_us);
task = kthread_create(ina2xx_capture_thread, (void *)indio_dev,
"%s:%d-%uus", indio_dev->name, indio_dev->id,
sampling_us);
if (IS_ERR(task))
return PTR_ERR(task);
return PTR_ERR_OR_ZERO(chip->task);
get_task_struct(task);
wake_up_process(task);
chip->task = task;
return 0;
}
static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
@ -848,6 +856,7 @@ static int ina2xx_buffer_disable(struct iio_dev *indio_dev)
if (chip->task) {
kthread_stop(chip->task);
put_task_struct(chip->task);
chip->task = NULL;
}

View File

@ -1577,7 +1577,6 @@ static int max1363_probe(struct i2c_client *client,
struct max1363_state *st;
struct iio_dev *indio_dev;
struct regulator *vref;
const struct of_device_id *match;
indio_dev = devm_iio_device_alloc(&client->dev,
sizeof(struct max1363_state));
@ -1604,11 +1603,8 @@ static int max1363_probe(struct i2c_client *client,
/* this is only used for device removal purposes */
i2c_set_clientdata(client, indio_dev);
match = of_match_device(of_match_ptr(max1363_of_match),
&client->dev);
if (match)
st->chip_info = of_device_get_match_data(&client->dev);
else
st->chip_info = of_device_get_match_data(&client->dev);
if (!st->chip_info)
st->chip_info = &max1363_chip_info_tbl[id->driver_data];
st->client = client;

View File

@ -922,6 +922,11 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
.name = "meson-meson8b-saradc",
};
static const struct meson_sar_adc_data meson_sar_adc_meson8m2_data = {
.param = &meson_sar_adc_meson8_param,
.name = "meson-meson8m2-saradc",
};
static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
.param = &meson_sar_adc_gxbb_param,
.name = "meson-gxbb-saradc",
@ -951,6 +956,10 @@ static const struct of_device_id meson_sar_adc_of_match[] = {
.compatible = "amlogic,meson8b-saradc",
.data = &meson_sar_adc_meson8b_data,
},
{
.compatible = "amlogic,meson8m2-saradc",
.data = &meson_sar_adc_meson8m2_data,
},
{
.compatible = "amlogic,meson-gxbb-saradc",
.data = &meson_sar_adc_gxbb_data,

View File

@ -0,0 +1,522 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Spreadtrum Communications Inc.
#include <linux/hwspinlock.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
/* PMIC global registers definition */
#define SC27XX_MODULE_EN 0xc08
#define SC27XX_MODULE_ADC_EN BIT(5)
#define SC27XX_ARM_CLK_EN 0xc10
#define SC27XX_CLK_ADC_EN BIT(5)
#define SC27XX_CLK_ADC_CLK_EN BIT(6)
/* ADC controller registers definition */
#define SC27XX_ADC_CTL 0x0
#define SC27XX_ADC_CH_CFG 0x4
#define SC27XX_ADC_DATA 0x4c
#define SC27XX_ADC_INT_EN 0x50
#define SC27XX_ADC_INT_CLR 0x54
#define SC27XX_ADC_INT_STS 0x58
#define SC27XX_ADC_INT_RAW 0x5c
/* Bits and mask definition for SC27XX_ADC_CTL register */
#define SC27XX_ADC_EN BIT(0)
#define SC27XX_ADC_CHN_RUN BIT(1)
#define SC27XX_ADC_12BIT_MODE BIT(2)
#define SC27XX_ADC_RUN_NUM_MASK GENMASK(7, 4)
#define SC27XX_ADC_RUN_NUM_SHIFT 4
/* Bits and mask definition for SC27XX_ADC_CH_CFG register */
#define SC27XX_ADC_CHN_ID_MASK GENMASK(4, 0)
#define SC27XX_ADC_SCALE_MASK GENMASK(10, 8)
#define SC27XX_ADC_SCALE_SHIFT 8
/* Bits definitions for SC27XX_ADC_INT_EN registers */
#define SC27XX_ADC_IRQ_EN BIT(0)
/* Bits definitions for SC27XX_ADC_INT_CLR registers */
#define SC27XX_ADC_IRQ_CLR BIT(0)
/* Mask definition for SC27XX_ADC_DATA register */
#define SC27XX_ADC_DATA_MASK GENMASK(11, 0)
/* Timeout (ms) for the trylock of hardware spinlocks */
#define SC27XX_ADC_HWLOCK_TIMEOUT 5000
/* Maximum ADC channel number */
#define SC27XX_ADC_CHANNEL_MAX 32
/* ADC voltage ratio definition */
#define SC27XX_VOLT_RATIO(n, d) \
(((n) << SC27XX_RATIO_NUMERATOR_OFFSET) | (d))
#define SC27XX_RATIO_NUMERATOR_OFFSET 16
#define SC27XX_RATIO_DENOMINATOR_MASK GENMASK(15, 0)
struct sc27xx_adc_data {
struct device *dev;
struct regmap *regmap;
/*
* One hardware spinlock to synchronize between the multiple
* subsystems which will access the unique ADC controller.
*/
struct hwspinlock *hwlock;
struct completion completion;
int channel_scale[SC27XX_ADC_CHANNEL_MAX];
u32 base;
int value;
int irq;
};
struct sc27xx_adc_linear_graph {
int volt0;
int adc0;
int volt1;
int adc1;
};
/*
* According to the datasheet, we can convert one ADC value to one voltage value
* through 2 points in the linear graph. If the voltage is less than 1.2v, we
* should use the small-scale graph, and if more than 1.2v, we should use the
* big-scale graph.
*/
static const struct sc27xx_adc_linear_graph big_scale_graph = {
4200, 3310,
3600, 2832,
};
static const struct sc27xx_adc_linear_graph small_scale_graph = {
1000, 3413,
100, 341,
};
static int sc27xx_adc_get_ratio(int channel, int scale)
{
switch (channel) {
case 1:
case 2:
case 3:
case 4:
return scale ? SC27XX_VOLT_RATIO(400, 1025) :
SC27XX_VOLT_RATIO(1, 1);
case 5:
return SC27XX_VOLT_RATIO(7, 29);
case 6:
return SC27XX_VOLT_RATIO(375, 9000);
case 7:
case 8:
return scale ? SC27XX_VOLT_RATIO(100, 125) :
SC27XX_VOLT_RATIO(1, 1);
case 19:
return SC27XX_VOLT_RATIO(1, 3);
default:
return SC27XX_VOLT_RATIO(1, 1);
}
return SC27XX_VOLT_RATIO(1, 1);
}
static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
int scale, int *val)
{
int ret;
u32 tmp;
reinit_completion(&data->completion);
ret = hwspin_lock_timeout_raw(data->hwlock, SC27XX_ADC_HWLOCK_TIMEOUT);
if (ret) {
dev_err(data->dev, "timeout to get the hwspinlock\n");
return ret;
}
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN, SC27XX_ADC_EN);
if (ret)
goto unlock_adc;
/* Configure the channel id and scale */
tmp = (scale << SC27XX_ADC_SCALE_SHIFT) & SC27XX_ADC_SCALE_MASK;
tmp |= channel & SC27XX_ADC_CHN_ID_MASK;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CH_CFG,
SC27XX_ADC_CHN_ID_MASK | SC27XX_ADC_SCALE_MASK,
tmp);
if (ret)
goto disable_adc;
/* Select 12bit conversion mode, and only sample 1 time */
tmp = SC27XX_ADC_12BIT_MODE;
tmp |= (0 << SC27XX_ADC_RUN_NUM_SHIFT) & SC27XX_ADC_RUN_NUM_MASK;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_RUN_NUM_MASK | SC27XX_ADC_12BIT_MODE,
tmp);
if (ret)
goto disable_adc;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_CHN_RUN, SC27XX_ADC_CHN_RUN);
if (ret)
goto disable_adc;
wait_for_completion(&data->completion);
disable_adc:
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
SC27XX_ADC_EN, 0);
unlock_adc:
hwspin_unlock_raw(data->hwlock);
if (!ret)
*val = data->value;
return ret;
}
static irqreturn_t sc27xx_adc_isr(int irq, void *dev_id)
{
struct sc27xx_adc_data *data = dev_id;
int ret;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_CLR,
SC27XX_ADC_IRQ_CLR, SC27XX_ADC_IRQ_CLR);
if (ret)
return IRQ_RETVAL(ret);
ret = regmap_read(data->regmap, data->base + SC27XX_ADC_DATA,
&data->value);
if (ret)
return IRQ_RETVAL(ret);
data->value &= SC27XX_ADC_DATA_MASK;
complete(&data->completion);
return IRQ_HANDLED;
}
static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
int channel, int scale,
u32 *div_numerator, u32 *div_denominator)
{
u32 ratio = sc27xx_adc_get_ratio(channel, scale);
*div_numerator = ratio >> SC27XX_RATIO_NUMERATOR_OFFSET;
*div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK;
}
static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph,
int raw_adc)
{
int tmp;
tmp = (graph->volt0 - graph->volt1) * (raw_adc - graph->adc1);
tmp /= (graph->adc0 - graph->adc1);
tmp += graph->volt1;
return tmp < 0 ? 0 : tmp;
}
static int sc27xx_adc_convert_volt(struct sc27xx_adc_data *data, int channel,
int scale, int raw_adc)
{
u32 numerator, denominator;
u32 volt;
/*
* Convert ADC values to voltage values according to the linear graph,
* and channel 5 and channel 1 has been calibrated, so we can just
* return the voltage values calculated by the linear graph. But other
* channels need be calculated to the real voltage values with the
* voltage ratio.
*/
switch (channel) {
case 5:
return sc27xx_adc_to_volt(&big_scale_graph, raw_adc);
case 1:
return sc27xx_adc_to_volt(&small_scale_graph, raw_adc);
default:
volt = sc27xx_adc_to_volt(&small_scale_graph, raw_adc);
break;
}
sc27xx_adc_volt_ratio(data, channel, scale, &numerator, &denominator);
return (volt * denominator + numerator / 2) / numerator;
}
static int sc27xx_adc_read_processed(struct sc27xx_adc_data *data,
int channel, int scale, int *val)
{
int ret, raw_adc;
ret = sc27xx_adc_read(data, channel, scale, &raw_adc);
if (ret)
return ret;
*val = sc27xx_adc_convert_volt(data, channel, scale, raw_adc);
return 0;
}
static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct sc27xx_adc_data *data = iio_priv(indio_dev);
int scale = data->channel_scale[chan->channel];
int ret, tmp;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
ret = sc27xx_adc_read_processed(data, chan->channel, scale,
&tmp);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
*val = tmp;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = scale;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int sc27xx_adc_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct sc27xx_adc_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
data->channel_scale[chan->channel] = val;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info sc27xx_info = {
.read_raw = &sc27xx_adc_read_raw,
.write_raw = &sc27xx_adc_write_raw,
};
#define SC27XX_ADC_CHANNEL(index) { \
.type = IIO_VOLTAGE, \
.channel = index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \
BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "CH##index", \
.indexed = 1, \
}
static const struct iio_chan_spec sc27xx_channels[] = {
SC27XX_ADC_CHANNEL(0),
SC27XX_ADC_CHANNEL(1),
SC27XX_ADC_CHANNEL(2),
SC27XX_ADC_CHANNEL(3),
SC27XX_ADC_CHANNEL(4),
SC27XX_ADC_CHANNEL(5),
SC27XX_ADC_CHANNEL(6),
SC27XX_ADC_CHANNEL(7),
SC27XX_ADC_CHANNEL(8),
SC27XX_ADC_CHANNEL(9),
SC27XX_ADC_CHANNEL(10),
SC27XX_ADC_CHANNEL(11),
SC27XX_ADC_CHANNEL(12),
SC27XX_ADC_CHANNEL(13),
SC27XX_ADC_CHANNEL(14),
SC27XX_ADC_CHANNEL(15),
SC27XX_ADC_CHANNEL(16),
SC27XX_ADC_CHANNEL(17),
SC27XX_ADC_CHANNEL(18),
SC27XX_ADC_CHANNEL(19),
SC27XX_ADC_CHANNEL(20),
SC27XX_ADC_CHANNEL(21),
SC27XX_ADC_CHANNEL(22),
SC27XX_ADC_CHANNEL(23),
SC27XX_ADC_CHANNEL(24),
SC27XX_ADC_CHANNEL(25),
SC27XX_ADC_CHANNEL(26),
SC27XX_ADC_CHANNEL(27),
SC27XX_ADC_CHANNEL(28),
SC27XX_ADC_CHANNEL(29),
SC27XX_ADC_CHANNEL(30),
SC27XX_ADC_CHANNEL(31),
};
static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
{
int ret;
ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN,
SC27XX_MODULE_ADC_EN, SC27XX_MODULE_ADC_EN);
if (ret)
return ret;
/* Enable ADC work clock and controller clock */
ret = regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN);
if (ret)
goto disable_adc;
ret = regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
SC27XX_ADC_IRQ_EN, SC27XX_ADC_IRQ_EN);
if (ret)
goto disable_clk;
return 0;
disable_clk:
regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
disable_adc:
regmap_update_bits(data->regmap, SC27XX_MODULE_EN,
SC27XX_MODULE_ADC_EN, 0);
return ret;
}
static void sc27xx_adc_disable(void *_data)
{
struct sc27xx_adc_data *data = _data;
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_INT_EN,
SC27XX_ADC_IRQ_EN, 0);
/* Disable ADC work clock and controller clock */
regmap_update_bits(data->regmap, SC27XX_ARM_CLK_EN,
SC27XX_CLK_ADC_EN | SC27XX_CLK_ADC_CLK_EN, 0);
regmap_update_bits(data->regmap, SC27XX_MODULE_EN,
SC27XX_MODULE_ADC_EN, 0);
}
static void sc27xx_adc_free_hwlock(void *_data)
{
struct hwspinlock *hwlock = _data;
hwspin_lock_free(hwlock);
}
static int sc27xx_adc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct sc27xx_adc_data *sc27xx_data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data));
if (!indio_dev)
return -ENOMEM;
sc27xx_data = iio_priv(indio_dev);
sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!sc27xx_data->regmap) {
dev_err(&pdev->dev, "failed to get ADC regmap\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "reg", &sc27xx_data->base);
if (ret) {
dev_err(&pdev->dev, "failed to get ADC base address\n");
return ret;
}
sc27xx_data->irq = platform_get_irq(pdev, 0);
if (sc27xx_data->irq < 0) {
dev_err(&pdev->dev, "failed to get ADC irq number\n");
return sc27xx_data->irq;
}
ret = of_hwspin_lock_get_id(np, 0);
if (ret < 0) {
dev_err(&pdev->dev, "failed to get hwspinlock id\n");
return ret;
}
sc27xx_data->hwlock = hwspin_lock_request_specific(ret);
if (!sc27xx_data->hwlock) {
dev_err(&pdev->dev, "failed to request hwspinlock\n");
return -ENXIO;
}
ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock,
sc27xx_data->hwlock);
if (ret) {
sc27xx_adc_free_hwlock(sc27xx_data->hwlock);
dev_err(&pdev->dev, "failed to add hwspinlock action\n");
return ret;
}
init_completion(&sc27xx_data->completion);
sc27xx_data->dev = &pdev->dev;
ret = sc27xx_adc_enable(sc27xx_data);
if (ret) {
dev_err(&pdev->dev, "failed to enable ADC module\n");
return ret;
}
ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data);
if (ret) {
sc27xx_adc_disable(sc27xx_data);
dev_err(&pdev->dev, "failed to add ADC disable action\n");
return ret;
}
ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL,
sc27xx_adc_isr, IRQF_ONESHOT,
pdev->name, sc27xx_data);
if (ret) {
dev_err(&pdev->dev, "failed to request ADC irq\n");
return ret;
}
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &sc27xx_info;
indio_dev->channels = sc27xx_channels;
indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret)
dev_err(&pdev->dev, "could not register iio (ADC)");
return ret;
}
static const struct of_device_id sc27xx_adc_of_match[] = {
{ .compatible = "sprd,sc2731-adc", },
{ }
};
static struct platform_driver sc27xx_adc_driver = {
.probe = sc27xx_adc_probe,
.driver = {
.name = "sc27xx-adc",
.of_match_table = sc27xx_adc_of_match,
},
};
module_platform_driver(sc27xx_adc_driver);
MODULE_AUTHOR("Freeman Liu <freeman.liu@spreadtrum.com>");
MODULE_DESCRIPTION("Spreadtrum SC27XX ADC Driver");
MODULE_LICENSE("GPL v2");

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Texas Instruments ADS7950 SPI ADC driver
*
@ -10,15 +11,6 @@
* And also on hwmon/ads79xx.c
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
* Nishanth Menon
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/acpi.h>
@ -76,6 +68,9 @@ struct ti_ads7950_state {
__be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE]
____cacheline_aligned;
__be16 tx_buf[TI_ADS7950_MAX_CHAN];
__be16 single_tx;
__be16 single_rx;
};
struct ti_ads7950_chip_info {
@ -295,18 +290,26 @@ static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
static int ti_ads7950_scan_direct(struct ti_ads7950_state *st, unsigned int ch)
static int ti_ads7950_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
{
struct ti_ads7950_state *st = iio_priv(indio_dev);
int ret, cmd;
mutex_lock(&indio_dev->mlock);
cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
st->tx_buf[0] = cpu_to_be16(cmd);
st->single_tx = cpu_to_be16(cmd);
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret)
return ret;
goto out;
return be16_to_cpu(st->rx_buf[0]);
ret = be16_to_cpu(st->single_rx);
out:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int ti_ads7950_get_range(struct ti_ads7950_state *st)
@ -338,13 +341,7 @@ static int ti_ads7950_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret < 0)
return ret;
ret = ti_ads7950_scan_direct(st, chan->address);
iio_device_release_direct_mode(indio_dev);
ret = ti_ads7950_scan_direct(indio_dev, chan->address);
if (ret < 0)
return ret;
@ -410,13 +407,13 @@ static int ti_ads7950_probe(struct spi_device *spi)
* was read at the end of the first transfer.
*/
st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[0].tx_buf = &st->single_tx;
st->scan_single_xfer[0].len = 2;
st->scan_single_xfer[0].cs_change = 1;
st->scan_single_xfer[1].tx_buf = &st->tx_buf[0];
st->scan_single_xfer[1].tx_buf = &st->single_tx;
st->scan_single_xfer[1].len = 2;
st->scan_single_xfer[1].cs_change = 1;
st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[2].rx_buf = &st->single_rx;
st->scan_single_xfer[2].len = 2;
spi_message_init_with_transfers(&st->scan_single_msg,

View File

@ -341,8 +341,6 @@ static int xadc_zynq_setup(struct platform_device *pdev,
pcap_rate = clk_get_rate(xadc->clk);
if (tck_rate > XADC_ZYNQ_TCK_RATE_MAX)
tck_rate = XADC_ZYNQ_TCK_RATE_MAX;
if (tck_rate > pcap_rate / 2) {
div = 2;
} else {
@ -1045,7 +1043,7 @@ static int xadc_parse_dt(struct iio_dev *indio_dev, struct device_node *np,
unsigned int num_channels;
const char *external_mux;
u32 ext_mux_chan;
int reg;
u32 reg;
int ret;
*conf = 0;

View File

@ -380,8 +380,7 @@ void st_sensors_of_name_probe(struct device *dev,
return;
/* The name from the OF match takes precedence if present */
strncpy(name, of_id->data, len);
name[len - 1] = '\0';
strlcpy(name, of_id->data, len);
}
EXPORT_SYMBOL(st_sensors_of_name_probe);
#else

View File

@ -167,6 +167,16 @@ config AD5755
To compile this driver as a module, choose M here: the
module will be called ad5755.
config AD5758
tristate "Analog Devices AD5758 DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD5758 single channel
Digital to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5758.
config AD5761
tristate "Analog Devices AD5761/61R/21/21R DAC driver"
depends on SPI_MASTER

View File

@ -16,6 +16,7 @@ obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
obj-$(CONFIG_AD5592R) += ad5592r.o
obj-$(CONFIG_AD5593R) += ad5593r.o
obj-$(CONFIG_AD5755) += ad5755.o
obj-$(CONFIG_AD5755) += ad5758.o
obj-$(CONFIG_AD5761) += ad5761.o
obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o

897
drivers/iio/dac/ad5758.c Normal file
View File

@ -0,0 +1,897 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* AD5758 Digital to analog converters driver
*
* Copyright 2018 Analog Devices Inc.
*
* TODO: Currently CRC is not supported in this driver
*/
#include <linux/bsearch.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* AD5758 registers definition */
#define AD5758_NOP 0x00
#define AD5758_DAC_INPUT 0x01
#define AD5758_DAC_OUTPUT 0x02
#define AD5758_CLEAR_CODE 0x03
#define AD5758_USER_GAIN 0x04
#define AD5758_USER_OFFSET 0x05
#define AD5758_DAC_CONFIG 0x06
#define AD5758_SW_LDAC 0x07
#define AD5758_KEY 0x08
#define AD5758_GP_CONFIG1 0x09
#define AD5758_GP_CONFIG2 0x0A
#define AD5758_DCDC_CONFIG1 0x0B
#define AD5758_DCDC_CONFIG2 0x0C
#define AD5758_WDT_CONFIG 0x0F
#define AD5758_DIGITAL_DIAG_CONFIG 0x10
#define AD5758_ADC_CONFIG 0x11
#define AD5758_FAULT_PIN_CONFIG 0x12
#define AD5758_TWO_STAGE_READBACK_SELECT 0x13
#define AD5758_DIGITAL_DIAG_RESULTS 0x14
#define AD5758_ANALOG_DIAG_RESULTS 0x15
#define AD5758_STATUS 0x16
#define AD5758_CHIP_ID 0x17
#define AD5758_FREQ_MONITOR 0x18
#define AD5758_DEVICE_ID_0 0x19
#define AD5758_DEVICE_ID_1 0x1A
#define AD5758_DEVICE_ID_2 0x1B
#define AD5758_DEVICE_ID_3 0x1C
/* AD5758_DAC_CONFIG */
#define AD5758_DAC_CONFIG_RANGE_MSK GENMASK(3, 0)
#define AD5758_DAC_CONFIG_RANGE_MODE(x) (((x) & 0xF) << 0)
#define AD5758_DAC_CONFIG_INT_EN_MSK BIT(5)
#define AD5758_DAC_CONFIG_INT_EN_MODE(x) (((x) & 0x1) << 5)
#define AD5758_DAC_CONFIG_OUT_EN_MSK BIT(6)
#define AD5758_DAC_CONFIG_OUT_EN_MODE(x) (((x) & 0x1) << 6)
#define AD5758_DAC_CONFIG_SR_EN_MSK BIT(8)
#define AD5758_DAC_CONFIG_SR_EN_MODE(x) (((x) & 0x1) << 8)
#define AD5758_DAC_CONFIG_SR_CLOCK_MSK GENMASK(12, 9)
#define AD5758_DAC_CONFIG_SR_CLOCK_MODE(x) (((x) & 0xF) << 9)
#define AD5758_DAC_CONFIG_SR_STEP_MSK GENMASK(15, 13)
#define AD5758_DAC_CONFIG_SR_STEP_MODE(x) (((x) & 0x7) << 13)
/* AD5758_KEY */
#define AD5758_KEY_CODE_RESET_1 0x15FA
#define AD5758_KEY_CODE_RESET_2 0xAF51
#define AD5758_KEY_CODE_SINGLE_ADC_CONV 0x1ADC
#define AD5758_KEY_CODE_RESET_WDT 0x0D06
#define AD5758_KEY_CODE_CALIB_MEM_REFRESH 0xFCBA
/* AD5758_DCDC_CONFIG1 */
#define AD5758_DCDC_CONFIG1_DCDC_VPROG_MSK GENMASK(4, 0)
#define AD5758_DCDC_CONFIG1_DCDC_VPROG_MODE(x) (((x) & 0x1F) << 0)
#define AD5758_DCDC_CONFIG1_DCDC_MODE_MSK GENMASK(6, 5)
#define AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(x) (((x) & 0x3) << 5)
#define AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK BIT(7)
#define AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(x) (((x) & 0x1) << 7)
/* AD5758_DCDC_CONFIG2 */
#define AD5758_DCDC_CONFIG2_ILIMIT_MSK GENMASK(3, 1)
#define AD5758_DCDC_CONFIG2_ILIMIT_MODE(x) (((x) & 0x7) << 1)
#define AD5758_DCDC_CONFIG2_INTR_SAT_3WI_MSK BIT(11)
#define AD5758_DCDC_CONFIG2_BUSY_3WI_MSK BIT(12)
/* AD5758_DIGITAL_DIAG_RESULTS */
#define AD5758_CAL_MEM_UNREFRESHED_MSK BIT(15)
#define AD5758_WR_FLAG_MSK(x) (0x80 | ((x) & 0x1F))
#define AD5758_FULL_SCALE_MICRO 65535000000ULL
/**
* struct ad5758_state - driver instance specific data
* @spi: spi_device
* @lock: mutex lock
* @out_range: struct which stores the output range
* @dc_dc_mode: variable which stores the mode of operation
* @dc_dc_ilim: variable which stores the dc-to-dc converter current limit
* @slew_time: variable which stores the target slew time
* @pwr_down: variable which contains whether a channel is powered down or not
* @data: spi transfer buffers
*/
struct ad5758_range {
int reg;
int min;
int max;
};
struct ad5758_state {
struct spi_device *spi;
struct mutex lock;
struct ad5758_range out_range;
unsigned int dc_dc_mode;
unsigned int dc_dc_ilim;
unsigned int slew_time;
bool pwr_down;
__be32 d32[3];
};
/**
* Output ranges corresponding to bits [3:0] from DAC_CONFIG register
* 0000: 0 V to 5 V voltage range
* 0001: 0 V to 10 V voltage range
* 0010: ±5 V voltage range
* 0011: ±10 V voltage range
* 1000: 0 mA to 20 mA current range
* 1001: 0 mA to 24 mA current range
* 1010: 4 mA to 20 mA current range
* 1011: ±20 mA current range
* 1100: ±24 mA current range
* 1101: -1 mA to +22 mA current range
*/
enum ad5758_output_range {
AD5758_RANGE_0V_5V,
AD5758_RANGE_0V_10V,
AD5758_RANGE_PLUSMINUS_5V,
AD5758_RANGE_PLUSMINUS_10V,
AD5758_RANGE_0mA_20mA = 8,
AD5758_RANGE_0mA_24mA,
AD5758_RANGE_4mA_24mA,
AD5758_RANGE_PLUSMINUS_20mA,
AD5758_RANGE_PLUSMINUS_24mA,
AD5758_RANGE_MINUS_1mA_PLUS_22mA,
};
enum ad5758_dc_dc_mode {
AD5758_DCDC_MODE_POWER_OFF,
AD5758_DCDC_MODE_DPC_CURRENT,
AD5758_DCDC_MODE_DPC_VOLTAGE,
AD5758_DCDC_MODE_PPC_CURRENT,
};
static const struct ad5758_range ad5758_voltage_range[] = {
{ AD5758_RANGE_0V_5V, 0, 5000000 },
{ AD5758_RANGE_0V_10V, 0, 10000000 },
{ AD5758_RANGE_PLUSMINUS_5V, -5000000, 5000000 },
{ AD5758_RANGE_PLUSMINUS_10V, -10000000, 10000000 }
};
static const struct ad5758_range ad5758_current_range[] = {
{ AD5758_RANGE_0mA_20mA, 0, 20000},
{ AD5758_RANGE_0mA_24mA, 0, 24000 },
{ AD5758_RANGE_4mA_24mA, 4, 24000 },
{ AD5758_RANGE_PLUSMINUS_20mA, -20000, 20000 },
{ AD5758_RANGE_PLUSMINUS_24mA, -24000, 24000 },
{ AD5758_RANGE_MINUS_1mA_PLUS_22mA, -1000, 22000 },
};
static const int ad5758_sr_clk[16] = {
240000, 200000, 150000, 128000, 64000, 32000, 16000, 8000, 4000, 2000,
1000, 512, 256, 128, 64, 16
};
static const int ad5758_sr_step[8] = {
4, 12, 64, 120, 256, 500, 1820, 2048
};
static const int ad5758_dc_dc_ilim[6] = {
150000, 200000, 250000, 300000, 350000, 400000
};
static int ad5758_spi_reg_read(struct ad5758_state *st, unsigned int addr)
{
struct spi_transfer t[] = {
{
.tx_buf = &st->d32[0],
.len = 4,
.cs_change = 1,
}, {
.tx_buf = &st->d32[1],
.rx_buf = &st->d32[2],
.len = 4,
},
};
int ret;
st->d32[0] = cpu_to_be32(
(AD5758_WR_FLAG_MSK(AD5758_TWO_STAGE_READBACK_SELECT) << 24) |
(addr << 8));
st->d32[1] = cpu_to_be32(AD5758_WR_FLAG_MSK(AD5758_NOP) << 24);
ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
if (ret < 0)
return ret;
return (be32_to_cpu(st->d32[2]) >> 8) & 0xFFFF;
}
static int ad5758_spi_reg_write(struct ad5758_state *st,
unsigned int addr,
unsigned int val)
{
st->d32[0] = cpu_to_be32((AD5758_WR_FLAG_MSK(addr) << 24) |
((val & 0xFFFF) << 8));
return spi_write(st->spi, &st->d32[0], sizeof(st->d32[0]));
}
static int ad5758_spi_write_mask(struct ad5758_state *st,
unsigned int addr,
unsigned long int mask,
unsigned int val)
{
int regval;
regval = ad5758_spi_reg_read(st, addr);
if (regval < 0)
return regval;
regval &= ~mask;
regval |= val;
return ad5758_spi_reg_write(st, addr, regval);
}
static int cmpfunc(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
static int ad5758_find_closest_match(const int *array,
unsigned int size, int val)
{
int i;
for (i = 0; i < size; i++) {
if (val <= array[i])
return i;
}
return size - 1;
}
static int ad5758_wait_for_task_complete(struct ad5758_state *st,
unsigned int reg,
unsigned int mask)
{
unsigned int timeout;
int ret;
timeout = 10;
do {
ret = ad5758_spi_reg_read(st, reg);
if (ret < 0)
return ret;
if (!(ret & mask))
return 0;
usleep_range(100, 1000);
} while (--timeout);
dev_err(&st->spi->dev,
"Error reading bit 0x%x in 0x%x register\n", mask, reg);
return -EIO;
}
static int ad5758_calib_mem_refresh(struct ad5758_state *st)
{
int ret;
ret = ad5758_spi_reg_write(st, AD5758_KEY,
AD5758_KEY_CODE_CALIB_MEM_REFRESH);
if (ret < 0) {
dev_err(&st->spi->dev,
"Failed to initiate a calibration memory refresh\n");
return ret;
}
/* Wait to allow time for the internal calibrations to complete */
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
AD5758_CAL_MEM_UNREFRESHED_MSK);
}
static int ad5758_soft_reset(struct ad5758_state *st)
{
int ret;
ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_1);
if (ret < 0)
return ret;
ret = ad5758_spi_reg_write(st, AD5758_KEY, AD5758_KEY_CODE_RESET_2);
/* Perform a software reset and wait at least 100us */
usleep_range(100, 1000);
return ret;
}
static int ad5758_set_dc_dc_conv_mode(struct ad5758_state *st,
enum ad5758_dc_dc_mode mode)
{
int ret;
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1,
AD5758_DCDC_CONFIG1_DCDC_MODE_MSK,
AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(mode));
if (ret < 0)
return ret;
/*
* Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0.
* This allows the 3-wire interface communication to complete.
*/
ret = ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2,
AD5758_DCDC_CONFIG2_BUSY_3WI_MSK);
if (ret < 0)
return ret;
st->dc_dc_mode = mode;
return ret;
}
static int ad5758_set_dc_dc_ilim(struct ad5758_state *st, unsigned int ilim)
{
int ret;
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG2,
AD5758_DCDC_CONFIG2_ILIMIT_MSK,
AD5758_DCDC_CONFIG2_ILIMIT_MODE(ilim));
if (ret < 0)
return ret;
/*
* Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0.
* This allows the 3-wire interface communication to complete.
*/
return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2,
AD5758_DCDC_CONFIG2_BUSY_3WI_MSK);
}
static int ad5758_slew_rate_set(struct ad5758_state *st,
unsigned int sr_clk_idx,
unsigned int sr_step_idx)
{
unsigned int mode;
unsigned long int mask;
int ret;
mask = AD5758_DAC_CONFIG_SR_EN_MSK |
AD5758_DAC_CONFIG_SR_CLOCK_MSK |
AD5758_DAC_CONFIG_SR_STEP_MSK;
mode = AD5758_DAC_CONFIG_SR_EN_MODE(1) |
AD5758_DAC_CONFIG_SR_STEP_MODE(sr_step_idx) |
AD5758_DAC_CONFIG_SR_CLOCK_MODE(sr_clk_idx);
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG, mask, mode);
if (ret < 0)
return ret;
/* Wait to allow time for the internal calibrations to complete */
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
AD5758_CAL_MEM_UNREFRESHED_MSK);
}
static int ad5758_slew_rate_config(struct ad5758_state *st)
{
unsigned int sr_clk_idx, sr_step_idx;
int i, res;
s64 diff_new, diff_old;
u64 sr_step, calc_slew_time;
sr_clk_idx = 0;
sr_step_idx = 0;
diff_old = S64_MAX;
/*
* The slew time can be determined by using the formula:
* Slew Time = (Full Scale Out / (Step Size x Update Clk Freq))
* where Slew time is expressed in microseconds
* Given the desired slew time, the following algorithm determines the
* best match for the step size and the update clock frequency.
*/
for (i = 0; i < ARRAY_SIZE(ad5758_sr_clk); i++) {
/*
* Go through each valid update clock freq and determine a raw
* value for the step size by using the formula:
* Step Size = Full Scale Out / (Update Clk Freq * Slew Time)
*/
sr_step = AD5758_FULL_SCALE_MICRO;
do_div(sr_step, ad5758_sr_clk[i]);
do_div(sr_step, st->slew_time);
/*
* After a raw value for step size was determined, find the
* closest valid match
*/
res = ad5758_find_closest_match(ad5758_sr_step,
ARRAY_SIZE(ad5758_sr_step),
sr_step);
/* Calculate the slew time */
calc_slew_time = AD5758_FULL_SCALE_MICRO;
do_div(calc_slew_time, ad5758_sr_step[res]);
do_div(calc_slew_time, ad5758_sr_clk[i]);
/*
* Determine with how many microseconds the calculated slew time
* is different from the desired slew time and store the diff
* for the next iteration
*/
diff_new = abs(st->slew_time - calc_slew_time);
if (diff_new < diff_old) {
diff_old = diff_new;
sr_clk_idx = i;
sr_step_idx = res;
}
}
return ad5758_slew_rate_set(st, sr_clk_idx, sr_step_idx);
}
static int ad5758_set_out_range(struct ad5758_state *st, int range)
{
int ret;
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
AD5758_DAC_CONFIG_RANGE_MSK,
AD5758_DAC_CONFIG_RANGE_MODE(range));
if (ret < 0)
return ret;
/* Wait to allow time for the internal calibrations to complete */
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
AD5758_CAL_MEM_UNREFRESHED_MSK);
}
static int ad5758_fault_prot_switch_en(struct ad5758_state *st, bool enable)
{
int ret;
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1,
AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK,
AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(enable));
if (ret < 0)
return ret;
/*
* Poll the BUSY_3WI bit in the DCDC_CONFIG2 register until it is 0.
* This allows the 3-wire interface communication to complete.
*/
return ad5758_wait_for_task_complete(st, AD5758_DCDC_CONFIG2,
AD5758_DCDC_CONFIG2_BUSY_3WI_MSK);
}
static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable)
{
int ret;
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
AD5758_DAC_CONFIG_INT_EN_MSK,
AD5758_DAC_CONFIG_INT_EN_MODE(enable));
if (ret < 0)
return ret;
/* Wait to allow time for the internal calibrations to complete */
return ad5758_wait_for_task_complete(st, AD5758_DIGITAL_DIAG_RESULTS,
AD5758_CAL_MEM_UNREFRESHED_MSK);
}
static int ad5758_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
unsigned int *readval)
{
struct ad5758_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->lock);
if (readval) {
ret = ad5758_spi_reg_read(st, reg);
if (ret < 0) {
mutex_unlock(&st->lock);
return ret;
}
*readval = ret;
ret = 0;
} else {
ret = ad5758_spi_reg_write(st, reg, writeval);
}
mutex_unlock(&st->lock);
return ret;
}
static int ad5758_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
struct ad5758_state *st = iio_priv(indio_dev);
int max, min, ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
ret = ad5758_spi_reg_read(st, AD5758_DAC_INPUT);
mutex_unlock(&st->lock);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
min = st->out_range.min;
max = st->out_range.max;
*val = (max - min) / 1000;
*val2 = 16;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
min = st->out_range.min;
max = st->out_range.max;
*val = ((min * (1 << 16)) / (max - min)) / 1000;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int ad5758_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
{
struct ad5758_state *st = iio_priv(indio_dev);
int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
ret = ad5758_spi_reg_write(st, AD5758_DAC_INPUT, val);
mutex_unlock(&st->lock);
return ret;
default:
return -EINVAL;
}
}
static ssize_t ad5758_read_powerdown(struct iio_dev *indio_dev,
uintptr_t priv,
const struct iio_chan_spec *chan,
char *buf)
{
struct ad5758_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
}
static ssize_t ad5758_write_powerdown(struct iio_dev *indio_dev,
uintptr_t priv,
struct iio_chan_spec const *chan,
const char *buf, size_t len)
{
struct ad5758_state *st = iio_priv(indio_dev);
bool pwr_down;
unsigned int dcdc_config1_mode, dc_dc_mode, dac_config_mode, val;
unsigned long int dcdc_config1_msk, dac_config_msk;
int ret;
ret = kstrtobool(buf, &pwr_down);
if (ret)
return ret;
mutex_lock(&st->lock);
if (pwr_down) {
dc_dc_mode = AD5758_DCDC_MODE_POWER_OFF;
val = 0;
} else {
dc_dc_mode = st->dc_dc_mode;
val = 1;
}
dcdc_config1_mode = AD5758_DCDC_CONFIG1_DCDC_MODE_MODE(dc_dc_mode) |
AD5758_DCDC_CONFIG1_PROT_SW_EN_MODE(val);
dcdc_config1_msk = AD5758_DCDC_CONFIG1_DCDC_MODE_MSK |
AD5758_DCDC_CONFIG1_PROT_SW_EN_MSK;
ret = ad5758_spi_write_mask(st, AD5758_DCDC_CONFIG1,
dcdc_config1_msk,
dcdc_config1_mode);
if (ret < 0)
goto err_unlock;
dac_config_mode = AD5758_DAC_CONFIG_OUT_EN_MODE(val) |
AD5758_DAC_CONFIG_INT_EN_MODE(val);
dac_config_msk = AD5758_DAC_CONFIG_OUT_EN_MSK |
AD5758_DAC_CONFIG_INT_EN_MSK;
ret = ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
dac_config_msk,
dac_config_mode);
if (ret < 0)
goto err_unlock;
st->pwr_down = pwr_down;
err_unlock:
mutex_unlock(&st->lock);
return ret ? ret : len;
}
static const struct iio_info ad5758_info = {
.read_raw = ad5758_read_raw,
.write_raw = ad5758_write_raw,
.debugfs_reg_access = &ad5758_reg_access,
};
static const struct iio_chan_spec_ext_info ad5758_ext_info[] = {
{
.name = "powerdown",
.read = ad5758_read_powerdown,
.write = ad5758_write_powerdown,
.shared = IIO_SHARED_BY_TYPE,
},
{ }
};
#define AD5758_DAC_CHAN(_chan_type) { \
.type = (_chan_type), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.indexed = 1, \
.output = 1, \
.ext_info = ad5758_ext_info, \
}
static const struct iio_chan_spec ad5758_voltage_ch[] = {
AD5758_DAC_CHAN(IIO_VOLTAGE)
};
static const struct iio_chan_spec ad5758_current_ch[] = {
AD5758_DAC_CHAN(IIO_CURRENT)
};
static bool ad5758_is_valid_mode(enum ad5758_dc_dc_mode mode)
{
switch (mode) {
case AD5758_DCDC_MODE_DPC_CURRENT:
case AD5758_DCDC_MODE_DPC_VOLTAGE:
case AD5758_DCDC_MODE_PPC_CURRENT:
return true;
default:
return false;
}
}
static int ad5758_crc_disable(struct ad5758_state *st)
{
unsigned int mask;
mask = (AD5758_WR_FLAG_MSK(AD5758_DIGITAL_DIAG_CONFIG) << 24) | 0x5C3A;
st->d32[0] = cpu_to_be32(mask);
return spi_write(st->spi, &st->d32[0], 4);
}
static int ad5758_find_out_range(struct ad5758_state *st,
const struct ad5758_range *range,
unsigned int size,
int min, int max)
{
int i;
for (i = 0; i < size; i++) {
if ((min == range[i].min) && (max == range[i].max)) {
st->out_range.reg = range[i].reg;
st->out_range.min = range[i].min;
st->out_range.max = range[i].max;
return 0;
}
}
return -EINVAL;
}
static int ad5758_parse_dt(struct ad5758_state *st)
{
unsigned int tmp, tmparray[2], size;
const struct ad5758_range *range;
int *index, ret;
st->dc_dc_ilim = 0;
ret = device_property_read_u32(&st->spi->dev,
"adi,dc-dc-ilim-microamp", &tmp);
if (ret) {
dev_dbg(&st->spi->dev,
"Missing \"dc-dc-ilim-microamp\" property\n");
} else {
index = bsearch(&tmp, ad5758_dc_dc_ilim,
ARRAY_SIZE(ad5758_dc_dc_ilim),
sizeof(int), cmpfunc);
if (!index)
dev_dbg(&st->spi->dev, "dc-dc-ilim out of range\n");
else
st->dc_dc_ilim = index - ad5758_dc_dc_ilim;
}
ret = device_property_read_u32(&st->spi->dev, "adi,dc-dc-mode",
&st->dc_dc_mode);
if (ret) {
dev_err(&st->spi->dev, "Missing \"dc-dc-mode\" property\n");
return ret;
}
if (!ad5758_is_valid_mode(st->dc_dc_mode))
return -EINVAL;
if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE) {
ret = device_property_read_u32_array(&st->spi->dev,
"adi,range-microvolt",
tmparray, 2);
if (ret) {
dev_err(&st->spi->dev,
"Missing \"range-microvolt\" property\n");
return ret;
}
range = ad5758_voltage_range;
size = ARRAY_SIZE(ad5758_voltage_range);
} else {
ret = device_property_read_u32_array(&st->spi->dev,
"adi,range-microamp",
tmparray, 2);
if (ret) {
dev_err(&st->spi->dev,
"Missing \"range-microamp\" property\n");
return ret;
}
range = ad5758_current_range;
size = ARRAY_SIZE(ad5758_current_range);
}
ret = ad5758_find_out_range(st, range, size, tmparray[0], tmparray[1]);
if (ret) {
dev_err(&st->spi->dev, "range invalid\n");
return ret;
}
ret = device_property_read_u32(&st->spi->dev, "adi,slew-time-us", &tmp);
if (ret) {
dev_dbg(&st->spi->dev, "Missing \"slew-time-us\" property\n");
st->slew_time = 0;
} else {
st->slew_time = tmp;
}
return 0;
}
static int ad5758_init(struct ad5758_state *st)
{
int regval, ret;
/* Disable CRC checks */
ret = ad5758_crc_disable(st);
if (ret < 0)
return ret;
/* Perform a software reset */
ret = ad5758_soft_reset(st);
if (ret < 0)
return ret;
/* Disable CRC checks */
ret = ad5758_crc_disable(st);
if (ret < 0)
return ret;
/* Perform a calibration memory refresh */
ret = ad5758_calib_mem_refresh(st);
if (ret < 0)
return ret;
regval = ad5758_spi_reg_read(st, AD5758_DIGITAL_DIAG_RESULTS);
if (regval < 0)
return regval;
/* Clear all the error flags */
ret = ad5758_spi_reg_write(st, AD5758_DIGITAL_DIAG_RESULTS, regval);
if (ret < 0)
return ret;
/* Set the dc-to-dc current limit */
ret = ad5758_set_dc_dc_ilim(st, st->dc_dc_ilim);
if (ret < 0)
return ret;
/* Configure the dc-to-dc controller mode */
ret = ad5758_set_dc_dc_conv_mode(st, st->dc_dc_mode);
if (ret < 0)
return ret;
/* Configure the output range */
ret = ad5758_set_out_range(st, st->out_range.reg);
if (ret < 0)
return ret;
/* Enable Slew Rate Control, set the slew rate clock and step */
if (st->slew_time) {
ret = ad5758_slew_rate_config(st);
if (ret < 0)
return ret;
}
/* Enable the VIOUT fault protection switch (FPS is closed) */
ret = ad5758_fault_prot_switch_en(st, 1);
if (ret < 0)
return ret;
/* Power up the DAC and internal (INT) amplifiers */
ret = ad5758_internal_buffers_en(st, 1);
if (ret < 0)
return ret;
/* Enable VIOUT */
return ad5758_spi_write_mask(st, AD5758_DAC_CONFIG,
AD5758_DAC_CONFIG_OUT_EN_MSK,
AD5758_DAC_CONFIG_OUT_EN_MODE(1));
}
static int ad5758_probe(struct spi_device *spi)
{
struct ad5758_state *st;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
mutex_init(&st->lock);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5758_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->num_channels = 1;
ret = ad5758_parse_dt(st);
if (ret < 0)
return ret;
if (st->dc_dc_mode == AD5758_DCDC_MODE_DPC_VOLTAGE)
indio_dev->channels = ad5758_voltage_ch;
else
indio_dev->channels = ad5758_current_ch;
ret = ad5758_init(st);
if (ret < 0) {
dev_err(&spi->dev, "AD5758 init failed\n");
return ret;
}
return devm_iio_device_register(&st->spi->dev, indio_dev);
}
static const struct spi_device_id ad5758_id[] = {
{ "ad5758", 0 },
{}
};
MODULE_DEVICE_TABLE(spi, ad5758_id);
static struct spi_driver ad5758_driver = {
.driver = {
.name = KBUILD_MODNAME,
},
.probe = ad5758_probe,
.id_table = ad5758_id,
};
module_spi_driver(ad5758_driver);
MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD5758 DAC");
MODULE_LICENSE("GPL v2");

View File

@ -87,12 +87,7 @@ static int ltc2632_read_raw(struct iio_dev *indio_dev,
int *val2,
long m)
{
struct ltc2632_chip_info *chip_info;
const struct ltc2632_state *st = iio_priv(indio_dev);
const struct spi_device_id *spi_dev_id = spi_get_device_id(st->spi_dev);
chip_info = (struct ltc2632_chip_info *)spi_dev_id->driver_data;
switch (m) {
case IIO_CHAN_INFO_SCALE:

View File

@ -97,9 +97,6 @@ static int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val)
static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn)
{
unsigned int shift;
shift = 12 - data->spec->resolution;
data->buf[1] = 0;
data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS;
@ -111,9 +108,6 @@ static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrd
static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn)
{
unsigned int shift;
shift = 16 - data->spec->resolution;
data->buf[2] = 0;
data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS;
data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) |

View File

@ -274,6 +274,15 @@ struct ad9523_state {
unsigned long vco_out_freq[AD9523_NUM_CLK_SRC];
unsigned char vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC];
/*
* Lock for accessing device registers. Some operations require
* multiple consecutive R/W operations, during which the device
* shouldn't be interrupted. The buffers are also shared across
* all operations so need to be protected on stand alone reads and
* writes.
*/
struct mutex lock;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@ -500,6 +509,7 @@ static ssize_t ad9523_store(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct ad9523_state *st = iio_priv(indio_dev);
bool state;
int ret;
@ -510,7 +520,7 @@ static ssize_t ad9523_store(struct device *dev,
if (!state)
return 0;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
switch ((u32)this_attr->address) {
case AD9523_SYNC:
ret = ad9523_sync(indio_dev);
@ -521,7 +531,7 @@ static ssize_t ad9523_store(struct device *dev,
default:
ret = -ENODEV;
}
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret ? ret : len;
}
@ -532,15 +542,16 @@ static ssize_t ad9523_show(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad9523_read(indio_dev, AD9523_READBACK_0);
if (ret >= 0) {
ret = sprintf(buf, "%d\n", !!(ret & (1 <<
(u32)this_attr->address)));
}
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
@ -623,9 +634,9 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
unsigned int code;
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
if (ret < 0)
return ret;
@ -642,7 +653,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) /
AD9523_CLK_DIST_DIV_REV(ret);
*val = code / 1000000;
*val2 = (code % 1000000) * 10;
*val2 = code % 1000000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
@ -659,7 +670,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
unsigned int reg;
int ret, tmp, code;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
if (ret < 0)
goto out;
@ -705,7 +716,7 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
ad9523_io_update(indio_dev);
out:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
@ -713,9 +724,10 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval,
unsigned int *readval)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
if (readval == NULL) {
ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval);
ad9523_io_update(indio_dev);
@ -728,7 +740,7 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,
}
out_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return ret;
}
@ -967,6 +979,8 @@ static int ad9523_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->reg = devm_regulator_get(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) {
ret = regulator_enable(st->reg);

View File

@ -81,9 +81,11 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
adis->tx[9] = (value >> 24) & 0xff;
adis->tx[6] = ADIS_WRITE_REG(reg + 2);
adis->tx[7] = (value >> 16) & 0xff;
/* fall through */
case 2:
adis->tx[4] = ADIS_WRITE_REG(reg + 1);
adis->tx[5] = (value >> 8) & 0xff;
/* fall through */
case 1:
adis->tx[2] = ADIS_WRITE_REG(reg);
adis->tx[3] = value & 0xff;
@ -167,6 +169,7 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
adis->tx[2] = ADIS_READ_REG(reg + 2);
adis->tx[3] = 0;
spi_message_add_tail(&xfers[1], &msg);
/* fall through */
case 2:
adis->tx[4] = ADIS_READ_REG(reg);
adis->tx[5] = 0;

View File

@ -103,6 +103,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
{
.whoami = INV_MPU6515_WHOAMI_VALUE,
.name = "MPU6515",
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
{
.whoami = INV_MPU6000_WHOAMI_VALUE,
.name = "MPU6000",

View File

@ -174,6 +174,7 @@ static int inv_mpu_remove(struct i2c_client *client)
static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6050", INV_MPU6050},
{"mpu6500", INV_MPU6500},
{"mpu6515", INV_MPU6515},
{"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
@ -192,6 +193,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,mpu6500",
.data = (void *)INV_MPU6500
},
{
.compatible = "invensense,mpu6515",
.data = (void *)INV_MPU6515
},
{
.compatible = "invensense,mpu9150",
.data = (void *)INV_MPU9150

View File

@ -71,6 +71,7 @@ struct inv_mpu6050_reg_map {
enum inv_devices {
INV_MPU6050,
INV_MPU6500,
INV_MPU6515,
INV_MPU6000,
INV_MPU9150,
INV_MPU9250,
@ -256,6 +257,7 @@ struct inv_mpu6050_state {
#define INV_MPU9150_WHOAMI_VALUE 0x68
#define INV_MPU9250_WHOAMI_VALUE 0x71
#define INV_MPU9255_WHOAMI_VALUE 0x73
#define INV_MPU6515_WHOAMI_VALUE 0x74
#define INV_ICM20608_WHOAMI_VALUE 0xAF
/* scan element definition */

View File

@ -298,8 +298,11 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
err = regmap_bulk_read(hw->regmap,
hw->settings->fifo_ops.fifo_diff.addr,
&fifo_status, sizeof(fifo_status));
if (err < 0)
if (err < 0) {
dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
err);
return err;
}
if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
return 0;
@ -313,8 +316,12 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
if (err < 0)
if (err < 0) {
dev_err(hw->dev,
"failed to read pattern from fifo (err=%d)\n",
err);
return err;
}
/*
* Data are written to the FIFO with a specific pattern
@ -385,8 +392,11 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
if (unlikely(reset_ts)) {
err = st_lsm6dsx_reset_hw_ts(hw);
if (err < 0)
if (err < 0) {
dev_err(hw->dev, "failed to reset hw ts (err=%d)\n",
err);
return err;
}
}
return read_len;
}

View File

@ -86,6 +86,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_INDEX] = "index",
[IIO_GRAVITY] = "gravity",
[IIO_POSITIONRELATIVE] = "positionrelative",
[IIO_PHASE] = "phase",
};
static const char * const iio_modifier_names[] = {
@ -109,6 +110,7 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_LIGHT_GREEN] = "green",
[IIO_MOD_LIGHT_BLUE] = "blue",
[IIO_MOD_LIGHT_UV] = "uv",
[IIO_MOD_LIGHT_DUV] = "duv",
[IIO_MOD_QUATERNION] = "quaternion",
[IIO_MOD_TEMP_AMBIENT] = "ambient",
[IIO_MOD_TEMP_OBJECT] = "object",

View File

@ -1,3 +1,4 @@
#
# Light sensors
#
@ -319,6 +320,17 @@ config PA12203001
This driver can also be built as a module. If so, the module
will be called pa12203001.
config SI1133
tristate "SI1133 UV Index Sensor and Ambient Light Sensor"
depends on I2C
select REGMAP_I2C
help
Say Y here if you want to build a driver for the Silicon Labs SI1133
UV Index Sensor and Ambient Light Sensor chip.
To compile this driver as a module, choose M here: the module will be
called si1133.
config SI1145
tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor"
depends on I2C

View File

@ -32,6 +32,7 @@ obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1133) += si1133.o
obj-$(CONFIG_SI1145) += si1145.o
obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o

1068
drivers/iio/light/si1133.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -94,9 +94,8 @@ static int st_press_i2c_probe(struct i2c_client *client,
if ((ret < 0) || (ret >= ST_PRESS_MAX))
return -ENODEV;
strncpy(client->name, st_press_id_table[ret].name,
strlcpy(client->name, st_press_id_table[ret].name,
sizeof(client->name));
client->name[sizeof(client->name) - 1] = '\0';
} else if (!id)
return -ENODEV;

View File

@ -20,6 +20,19 @@ endmenu
menu "Proximity and distance sensors"
config ISL29501
tristate "Intersil ISL29501 Time Of Flight sensor"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IIO_KFIFO_BUF
help
Say Y here if you want to build a driver for the Intersil ISL29501
Time of Flight sensor.
To compile this driver as a module, choose M here: the module will be
called isl29501.
config LIDAR_LITE_V2
tristate "PulsedLight LIDAR sensor"
select IIO_BUFFER

View File

@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_ISL29501) += isl29501.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o

File diff suppressed because it is too large Load Diff

View File

@ -116,45 +116,26 @@ static struct ad5933_platform_data ad5933_default_pdata = {
.vref_mv = 3300,
};
#define AD5933_CHANNEL(_type, _extend_name, _info_mask_separate, _address, \
_scan_index, _realbits) { \
.type = (_type), \
.extend_name = (_extend_name), \
.info_mask_separate = (_info_mask_separate), \
.address = (_address), \
.scan_index = (_scan_index), \
.scan_type = { \
.sign = 's', \
.realbits = (_realbits), \
.storagebits = 16, \
}, \
}
static const struct iio_chan_spec ad5933_channels[] = {
{
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.address = AD5933_REG_TEMP_DATA,
.scan_index = -1,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
}, { /* Ring Channels */
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.extend_name = "real",
.address = AD5933_REG_REAL_DATA,
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
},
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.extend_name = "imag",
.address = AD5933_REG_IMAG_DATA,
.scan_index = 1,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
},
},
AD5933_CHANNEL(IIO_TEMP, NULL, BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE), AD5933_REG_TEMP_DATA, -1, 14),
/* Ring Channels */
AD5933_CHANNEL(IIO_VOLTAGE, "real", 0, AD5933_REG_REAL_DATA, 0, 16),
AD5933_CHANNEL(IIO_VOLTAGE, "imag", 0, AD5933_REG_IMAG_DATA, 1, 16),
};
static int ad5933_i2c_write(struct i2c_client *client, u8 reg, u8 len, u8 *data)

View File

@ -45,6 +45,7 @@ enum iio_chan_type {
IIO_INDEX,
IIO_GRAVITY,
IIO_POSITIONRELATIVE,
IIO_PHASE,
};
enum iio_modifier {
@ -85,6 +86,7 @@ enum iio_modifier {
IIO_MOD_CO2,
IIO_MOD_VOC,
IIO_MOD_LIGHT_UV,
IIO_MOD_LIGHT_DUV,
};
enum iio_event_type {

View File

@ -59,6 +59,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_UVINDEX] = "uvindex",
[IIO_GRAVITY] = "gravity",
[IIO_POSITIONRELATIVE] = "positionrelative",
[IIO_PHASE] = "phase",
};
static const char * const iio_ev_type_text[] = {
@ -97,6 +98,7 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_LIGHT_GREEN] = "green",
[IIO_MOD_LIGHT_BLUE] = "blue",
[IIO_MOD_LIGHT_UV] = "uv",
[IIO_MOD_LIGHT_DUV] = "duv",
[IIO_MOD_QUATERNION] = "quaternion",
[IIO_MOD_TEMP_AMBIENT] = "ambient",
[IIO_MOD_TEMP_OBJECT] = "object",
@ -153,6 +155,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_UVINDEX:
case IIO_GRAVITY:
case IIO_POSITIONRELATIVE:
case IIO_PHASE:
break;
default:
return false;
@ -180,6 +183,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_MOD_LIGHT_GREEN:
case IIO_MOD_LIGHT_BLUE:
case IIO_MOD_LIGHT_UV:
case IIO_MOD_LIGHT_DUV:
case IIO_MOD_QUATERNION:
case IIO_MOD_TEMP_AMBIENT:
case IIO_MOD_TEMP_OBJECT: