Commit 02061181 authored by Linus Torvalds's avatar Linus Torvalds

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

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

  Lots and lots of tiny patches here, nothing major at all. Which is
  good, tiny cleanups is nice to see. No new huge driver removal or
  addition, this release cycle, although there are lots of good IIO
  driver changes, addtions, and movement from staging into the "real"
  part of the kernel, which is always great.

  Full details are in the shortlog, and all of these have been in
  linux-next for a while with no reported issues"

* tag 'staging-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (553 commits)
  staging: mt7621-mmc: Correct spelling mistakes in comments
  staging: wilc1000: fix missing read_write setting when reading data
  mt7621-mmc: char * array declaration might be better as static const
  mt7621-mmc: return statement in void function unnecessary
  mt7621-mmc: Alignment should match open parenthesis
  mt7621-mmc: Removed unnecessary blank lines
  mt7621-mmc: Fix some coding style issues
  staging: android: ashmem: doc: Fix spelling
  staging: rtl8188eu: cleanup brace coding style issues
  staging: rtl8188eu: add spaces around '&' in rtw_mlme_ext.c
  staging: rtl8188eu: change return type of is_basicrate() to bool
  staging: rtl8188eu: simplify null array initializations
  staging: rtl8188eu: change order of declarations to improve readability
  staging: rtl8188eu: make some arrays static in rtw_mlme_ext.c
  staging: rtl8188eu: constify some arrays
  staging: rtl8188eu: convert unsigned char arrays to u8
  staging: rtl8188eu: remove redundant declaration in rtw_mlme_ext.c
  staging: rtl8188eu: remove unused arrays WFD_OUI and WMM_INFO_OUI
  staging: rtl8188eu: remove unnecessary parentheses in rtw_mlme_ext.c
  staging: rtl8188eu: remove unnecessary comments in rtw_mlme_ext.c
  ...
parents 117eda8f 215852f4
......@@ -64,7 +64,7 @@ Optional properties for all bus drivers:
Example for a SPI device node:
lis302@0 {
accelerometer@0 {
compatible = "st,lis302dl-spi";
reg = <0>;
spi-max-frequency = <1000000>;
......@@ -89,7 +89,7 @@ Example for a SPI device node:
Example for a I2C device node:
lis331dlh: lis331dlh@18 {
lis331dlh: accelerometer@18 {
compatible = "st,lis331dlh", "st,lis3lv02d";
reg = <0x18>;
Vdd-supply = <&lis3_reg>;
......
* Analog Devices AD7949/AD7682/AD7689
Required properties:
- compatible: Should be one of
* "adi,ad7949"
* "adi,ad7682"
* "adi,ad7689"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
Example:
adc@0 {
compatible = "adi,ad7949";
reg = <0>;
vref-supply = <&vdd_supply>;
};
Common ADCs properties
Optional properties for child nodes:
- bipolar : Boolean, if set the channel is used in bipolar mode.
- diff-channels : Differential channels muxed for this ADC. The first value
specifies the positive input pin, the second value the negative
input pin.
Example:
adc@0 {
compatible = "some,adc";
...
channel@0 {
bipolar;
diff-channels = <0 1>;
...
};
channel@1 {
diff-channels = <2 3>;
...
};
};
Analog Devices AD7124 ADC device driver
Required properties for the AD7124:
- compatible: Must be one of "adi,ad7124-4" or "adi,ad7124-8"
- 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
Required properties:
* #address-cells: Must be 1.
* #size-cells: Must be 0.
Subnode(s) represent the external channels which are connected to the ADC.
Each subnode represents one channel and has the following properties:
Required properties:
* reg: The channel number. It can have up to 4 channels on ad7124-4
and 8 channels on ad7124-8, numbered from 0 to 15.
* diff-channels: see: Documentation/devicetree/bindings/iio/adc/adc.txt
Optional properties:
* bipolar: see: Documentation/devicetree/bindings/iio/adc/adc.txt
* adi,reference-select: Select the reference source to use when
converting on the the specific channel. Valid values are:
0: REFIN1(+)/REFIN1(−).
1: REFIN2(+)/REFIN2(−).
3: AVDD
If this field is left empty, internal reference is selected.
Optional properties:
- refin1-supply: refin1 supply can be used as reference for conversion.
- refin2-supply: refin2 supply can be used as reference for conversion.
- avdd-supply: avdd supply can be used as reference for conversion.
Example:
adc@0 {
compatible = "adi,ad7124-4";
reg = <0>;
spi-max-frequency = <5000000>;
interrupts = <25 2>;
interrupt-parent = <&gpio>;
refin1-supply = <&adc_vref>;
clocks = <&ad7124_mclk>;
clock-names = "mclk";
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
diff-channels = <0 1>;
adi,reference-select = <0>;
};
channel@1 {
reg = <1>;
bipolar;
diff-channels = <2 3>;
adi,reference-select = <0>;
};
channel@2 {
reg = <2>;
diff-channels = <4 5>;
};
channel@3 {
reg = <3>;
diff-channels = <6 7>;
};
};
......@@ -22,6 +22,12 @@ Required properties:
- vref-supply: the regulator supply for the ADC reference voltage
- #io-channel-cells: must be 1, see ../iio-bindings.txt
Optional properties:
- 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"
Example:
saradc: adc@8680 {
compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc";
......
......@@ -11,7 +11,7 @@ New driver handles the following
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
for exynos4412/5250 and s5pv210 controllers.
for exynos4412/5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
Must be "samsung,exynos3250-adc" for
......@@ -28,6 +28,8 @@ Required properties:
the ADC in s3c2443 and compatibles
Must be "samsung,s3c6410-adc" for
the ADC in s3c6410 and compatibles
Must be "samsung,s5pv210-adc" for
the ADC in s5pv210 and compatibles
- reg: List of ADC register address range
- The base address and range of ADC register
- The base address and range of ADC_PHY register (every
......
* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
Required properties:
- compatible: Should be "ti,adc128s052", "ti,adc122s021" or "ti,adc124s021"
- compatible: Should be one of:
- "ti,adc128s052"
- "ti,adc122s021"
- "ti,adc122s051"
- "ti,adc122s101"
- "ti,adc124s021"
- "ti,adc124s051"
- "ti,adc124s101"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
......
TI DAC7311 device tree bindings
Required properties:
- compatible: must be set to:
* "ti,dac7311"
* "ti,dac6311"
* "ti,dac5311"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
Optional properties:
- spi-max-frequency: Max SPI frequency to use
Example:
spi_master {
dac@0 {
compatible = "ti,dac7311";
reg = <0>; /* CS0 */
spi-max-frequency = <1000000>;
vref-supply = <&vdd_supply>;
};
};
......@@ -13,6 +13,7 @@ Required properties:
Optional properties:
- st,drdy-int-pin: the pin on the package that will be used to signal
"data ready" (valid values: 1 or 2).
- st,pullups : enable/disable internal i2c controller pullup resistors.
- drive-open-drain: the interrupt/data ready line will be configured
as open drain, which is useful if several sensors share the same
interrupt line. This is a boolean property.
......
VISHAY VCNL4035 - Ambient Light and proximity sensor
Link to datasheet: https://www.vishay.com/docs/84251/vcnl4035x01.pdf
Required properties:
-compatible: should be "vishay,vcnl4035"
-reg: I2C address of the sensor, should be 0x60
-interrupts: interrupt mapping for GPIO IRQ (level active low)
Example:
light-sensor@60 {
compatible = "vishay,vcnl4035";
reg = <0x60>;
interrupt-parent = <&gpio4>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
};
* PNI RM3100 3-axis magnetometer sensor
Required properties:
- compatible : should be "pni,rm3100"
- reg : the I2C address or SPI chip select number of the sensor.
Optional properties:
- interrupts: data ready (DRDY) from the chip.
The interrupts can be triggered on level high.
Example:
rm3100: rm3100@20 {
compatible = "pni,rm3100";
reg = <0x20>;
interrupt-parent = <&gpio0>;
interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
};
* Microchip MCP41010/41050/41100/42010/42050/42100 Digital Potentiometer
Datasheet publicly available at:
http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in
Documentation/devicetree/bindings/spi/spi-bus.txt
must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"microchip,mcp41010"
"microchip,mcp41050"
"microchip,mcp41100"
"microchip,mcp42010"
"microchip,mcp42050"
"microchip,mcp42100"
Example:
potentiometer@0 {
compatible = "microchip,mcp41010";
reg = <0>;
spi-max-frequency = <500000>;
};
Analog Devices AD2S90 Resolver-to-Digital Converter
https://www.analog.com/en/products/ad2s90.html
Required properties:
- compatible: should be "adi,ad2s90"
- reg: SPI chip select number for the device
- spi-max-frequency: set maximum clock frequency, must be 830000
- spi-cpol and spi-cpha:
Either SPI mode (0,0) or (1,1) must be used, so specify none or both of
spi-cpha, spi-cpol.
See for more details:
Documentation/devicetree/bindings/spi/spi-bus.txt
Note about max frequency:
Chip's max frequency, as specified in its datasheet, is 2Mhz. But a 600ns
delay is expected between the application of a logic LO to CS and the
application of SCLK, as also specified. And since the delay is not
implemented in the spi code, to satisfy it, SCLK's period should be at most
2 * 600ns, so the max frequency should be 1 / (2 * 6e-7), which gives
roughly 830000Hz.
Example:
resolver@0 {
compatible = "adi,ad2s90";
reg = <0>;
spi-max-frequency = <830000>;
spi-cpol;
spi-cpha;
};
......@@ -48,6 +48,7 @@ Accelerometers:
- st,lis3l02dq
- st,lis2dw12
- st,lis3dhh
- st,lis3de
Gyroscopes:
- st,l3g4200d-gyro
......@@ -67,6 +68,7 @@ Magnetometers:
- st,lsm303dlm-magn
- st,lis3mdl-magn
- st,lis2mdl
- st,lsm9ds1-magn
Pressure sensors:
- st,lps001wp-press
......
......@@ -305,6 +305,7 @@ pixcir PIXCIR MICROELECTRONICS Co., Ltd
plathome Plat'Home Co., Ltd.
plda PLDA
plx Broadcom Corporation (formerly PLX Technology)
pni PNI Sensor Corporation
portwell Portwell Inc.
poslab Poslab Technology Co., Ltd.
powervr PowerVR (deprecated, use img)
......@@ -417,6 +418,7 @@ vamrs Vamrs Ltd.
variscite Variscite Ltd.
via VIA Technologies, Inc.
virtio Virtual I/O Device Specification, developed by the OASIS consortium
vishay Vishay Intertechnology, Inc
vitesse Vitesse Semiconductor Corporation
vivante Vivante Corporation
vocore VoCore Studio
......
......@@ -846,6 +846,14 @@ S: Supported
F: drivers/iio/dac/ad5758.c
F: Documentation/devicetree/bindings/iio/dac/ad5758.txt
ANALOG DEVICES INC AD7124 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/ad7124.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt
ANALOG DEVICES INC AD9389B DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
......@@ -6906,6 +6914,14 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/touchscreen/htcpen.c
HTS221 TEMPERATURE-HUMIDITY IIO DRIVER
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
L: linux-iio@vger.kernel.org
W: http://www.st.com/
S: Maintained
F: drivers/iio/humidity/hts221*
F: Documentation/devicetree/bindings/iio/humidity/hts221.txt
HUAWEI ETHERNET DRIVER
M: Aviad Krawczyk <aviad.krawczyk@huawei.com>
L: netdev@vger.kernel.org
......@@ -12055,6 +12071,13 @@ M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
S: Maintained
F: drivers/pnp/
PNI RM3100 IIO DRIVER
M: Song Qiang <songqiang1304521@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/magnetometer/rm3100*
F: Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt
POSIX CLOCKS and TIMERS
M: Thomas Gleixner <tglx@linutronix.de>
L: linux-kernel@vger.kernel.org
......@@ -12840,7 +12863,8 @@ RENESAS R-CAR GYROADC DRIVER
M: Marek Vasut <marek.vasut@gmail.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/adc/rcar_gyro_adc.c
F: Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
F: drivers/iio/adc/rcar-gyroadc.c
RENESAS R-CAR I2C DRIVERS
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
......@@ -14275,6 +14299,14 @@ M: Jan-Benedict Glaw <jbglaw@lug-owl.de>
S: Maintained
F: arch/alpha/kernel/srm_env.c
ST LSM6DSx IMU IIO DRIVER
M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
L: linux-iio@vger.kernel.org
W: http://www.st.com/
S: Maintained
F: drivers/iio/imu/st_lsm6dsx/
F: Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
ST STM32 I2C/SMBUS DRIVER
M: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
L: linux-i2c@vger.kernel.org
......@@ -14360,8 +14392,8 @@ S: Odd Fixes
F: drivers/staging/vt665?/
STAGING - WILC1000 WIFI DRIVER
M: Aditya Shankar <aditya.shankar@microchip.com>
M: Ganesh Krishna <ganesh.krishna@microchip.com>
M: Adham Abozaeid <adham.abozaeid@microchip.com>
M: Ajay Singh <ajay.kathat@microchip.com>
L: linux-wireless@vger.kernel.org
S: Supported
F: drivers/staging/wilc1000/
......
......@@ -223,7 +223,7 @@ config IIO_ST_ACCEL_3AXIS
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL,
LNG2DM
LNG2DM, LIS3DE
This driver can also be built as a module. If so, these modules
will be created:
......
......@@ -1489,8 +1489,11 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ1013", KXCJK1013},
{"KXCJ1008", KXCJ91008},
{"KXCJ9000", KXCJ91008},
{"KIOX0009", KXTJ21009},
{"KIOX000A", KXCJ91008},
{"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */
{"KXTJ1009", KXTJ21009},
{"KXJ2109", KXTJ21009},
{"SMO8500", KXCJ91008},
{ },
};
......
......@@ -56,6 +56,7 @@ enum st_accel_type {
#define LNG2DM_ACCEL_DEV_NAME "lng2dm"
#define LIS2DW12_ACCEL_DEV_NAME "lis2dw12"
#define LIS3DHH_ACCEL_DEV_NAME "lis3dhh"
#define LIS3DE_ACCEL_DEV_NAME "lis3de"
/**
* struct st_sensors_platform_data - default accel platform data
......
......@@ -103,6 +103,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
[4] = LSM330DLC_ACCEL_DEV_NAME,
[5] = LSM303AGR_ACCEL_DEV_NAME,
[6] = LIS2DH12_ACCEL_DEV_NAME,
[7] = LIS3DE_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
......
......@@ -98,6 +98,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis2dw12",
.data = LIS2DW12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis3de",
.data = LIS3DE_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -135,6 +139,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LIS331DL_ACCEL_DEV_NAME },
{ LIS3LV02DL_ACCEL_DEV_NAME },
{ LIS2DW12_ACCEL_DEV_NAME },
{ LIS3DE_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
......
......@@ -90,6 +90,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis3dhh",
.data = LIS3DHH_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis3de",
.data = LIS3DE_ACCEL_DEV_NAME,
},
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -143,6 +147,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LIS3LV02DL_ACCEL_DEV_NAME },
{ LIS2DW12_ACCEL_DEV_NAME },
{ LIS3DHH_ACCEL_DEV_NAME },
{ LIS3DE_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
......
......@@ -10,6 +10,17 @@ config AD_SIGMA_DELTA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7124
tristate "Analog Devices AD7124 and similar sigma-delta ADCs driver"
depends on SPI_MASTER
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7124-4 and AD7124-8
SPI analog to digital converters (ADC).
To compile this driver as a module, choose M here: the module will be
called ad7124.
config AD7266
tristate "Analog Devices AD7265/AD7266 ADC driver"
depends on SPI_MASTER
......@@ -116,6 +127,16 @@ config AD7923
To compile this driver as a module, choose M here: the
module will be called ad7923.
config AD7949
tristate "Analog Devices AD7949 and similar ADCs driver"
depends on SPI
help
Say yes here to build support for Analog Devices
AD7949, AD7682, AD7689 8 Channel ADCs.
To compile this driver as a module, choose M here: the
module will be called ad7949.
config AD799X
tristate "Analog Devices AD799x ADC driver"
depends on I2C
......@@ -274,7 +295,7 @@ config EP93XX_ADC
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST)
depends on HAS_IOMEM
help
Core support for the ADC block found in the Samsung EXYNOS series
......
......@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7298) += ad7298.o
......@@ -14,6 +15,7 @@ obj-$(CONFIG_AD7766) += ad7766.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD7949) += ad7949.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/* ad7949.c - Analog Devices ADC driver 14/16 bits 4/8 channels
*
* Copyright (C) 2018 CMC NV
*
* http://www.analog.com/media/en/technical-documentation/data-sheets/AD7949.pdf
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#define AD7949_MASK_CHANNEL_SEL GENMASK(9, 7)
#define AD7949_MASK_TOTAL GENMASK(13, 0)
#define AD7949_OFFSET_CHANNEL_SEL 7
#define AD7949_CFG_READ_BACK 0x1
#define AD7949_CFG_REG_SIZE_BITS 14
enum {
ID_AD7949 = 0,
ID_AD7682,
ID_AD7689,
};
struct ad7949_adc_spec {
u8 num_channels;
u8 resolution;
};
static const struct ad7949_adc_spec ad7949_adc_spec[] = {
[ID_AD7949] = { .num_channels = 8, .resolution = 14 },
[ID_AD7682] = { .num_channels = 4, .resolution = 16 },
[ID_AD7689] = { .num_channels = 8, .resolution = 16 },
};
/**
* struct ad7949_adc_chip - AD ADC chip
* @lock: protects write sequences
* @vref: regulator generating Vref
* @iio_dev: reference to iio structure
* @spi: reference to spi structure
* @resolution: resolution of the chip
* @cfg: copy of the configuration register
* @current_channel: current channel in use
* @buffer: buffer to send / receive data to / from device
*/
struct ad7949_adc_chip {
struct mutex lock;
struct regulator *vref;
struct iio_dev *indio_dev;
struct spi_device *spi;
u8 resolution;
u16 cfg;
unsigned int current_channel;
u32 buffer ____cacheline_aligned;
};
static bool ad7949_spi_cfg_is_read_back(struct ad7949_adc_chip *ad7949_adc)
{
if (!(ad7949_adc->cfg & AD7949_CFG_READ_BACK))
return true;
return false;
}
static int ad7949_spi_bits_per_word(struct ad7949_adc_chip *ad7949_adc)
{
int ret = ad7949_adc->resolution;
if (ad7949_spi_cfg_is_read_back(ad7949_adc))
ret += AD7949_CFG_REG_SIZE_BITS;
return ret;
}
static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
u16 mask)
{
int ret;
int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
struct spi_message msg;
struct spi_transfer tx[] = {
{
.tx_buf = &ad7949_adc->buffer,
.len = 4,
.bits_per_word = bits_per_word,
},
};
ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
ad7949_adc->buffer = ad7949_adc->cfg << shift;
spi_message_init_with_transfers(&msg, tx, 1);
ret = spi_sync(ad7949_adc->spi, &msg);
/*
* This delay is to avoid a new request before the required time to
* send a new command to the device
*/
udelay(2);
return ret;
}
static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
unsigned int channel)
{
int ret;
int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
int mask = GENMASK(ad7949_adc->resolution, 0);
struct spi_message msg;
struct spi_transfer tx[] = {
{
.rx_buf = &ad7949_adc->buffer,
.len = 4,
.bits_per_word = bits_per_word,
},
};
ret = ad7949_spi_write_cfg(ad7949_adc,
channel << AD7949_OFFSET_CHANNEL_SEL,
AD7949_MASK_CHANNEL_SEL);
if (ret)
return ret;
ad7949_adc->buffer = 0;
spi_message_init_with_transfers(&msg, tx, 1);
ret = spi_sync(ad7949_adc->spi, &msg);
if (ret)
return ret;
/*
* This delay is to avoid a new request before the required time to
* send a new command to the device
*/
udelay(2);
ad7949_adc->current_channel = channel;
if (ad7949_spi_cfg_is_read_back(ad7949_adc))
*val = (ad7949_adc->buffer >> AD7949_CFG_REG_SIZE_BITS) & mask;
else
*val = ad7949_adc->buffer & mask;
return 0;
}
#define AD7949_ADC_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec ad7949_adc_channels[] = {
AD7949_ADC_CHANNEL(0),
AD7949_ADC_CHANNEL(1),
AD7949_ADC_CHANNEL(2),
AD7949_ADC_CHANNEL(3),
AD7949_ADC_CHANNEL(4),
AD7949_ADC_CHANNEL(5),
AD7949_ADC_CHANNEL(6),
AD7949_ADC_CHANNEL(7),
};
static int ad7949_spi_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
int ret;
if (!val)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&ad7949_adc->lock);
ret = ad7949_spi_read_channel(ad7949_adc, val, chan->channel);
mutex_unlock(&ad7949_adc->lock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(ad7949_adc->vref);
if (ret < 0)
return ret;
*val = ret / 5000;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad7949_spi_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int writeval,
unsigned int *readval)
{
struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
int ret = 0;
if (readval)
*readval = ad7949_adc->cfg;
else
ret = ad7949_spi_write_cfg(ad7949_adc,
writeval & AD7949_MASK_TOTAL, AD7949_MASK_TOTAL);
return ret;
}
static const struct iio_info ad7949_spi_info = {
.read_raw = ad7949_spi_read_raw,
.debugfs_reg_access = ad7949_spi_reg_access,
};
static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
{
int ret;
int val;
/* Sequencer disabled, CFG readback disabled, IN0 as default channel */
ad7949_adc->current_channel = 0;
ret = ad7949_spi_write_cfg(ad7949_adc, 0x3C79, AD7949_MASK_TOTAL);
/*
* Do two dummy conversions to apply the first configuration setting.
* Required only after the start up of the device.
*/
ad7949_spi_read_channel(ad7949_adc, &val, ad7949_adc->current_channel);
ad7949_spi_read_channel(ad7949_adc, &val, ad7949_adc->current_channel);
return ret;
}
static int ad7949_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
const struct ad7949_adc_spec *spec;
struct ad7949_adc_chip *ad7949_adc;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*ad7949_adc));
if (!indio_dev) {
dev_err(dev, "can not allocate iio device\n");
return -ENOMEM;
}
indio_dev->dev.parent = dev;
indio_dev->dev.of_node = dev->of_node;
indio_dev->info = &ad7949_spi_info;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad7949_adc_channels;
spi_set_drvdata(spi, indio_dev);
ad7949_adc = iio_priv(indio_dev);
ad7949_adc->indio_dev = indio_dev;
ad7949_adc->spi = spi;
spec = &ad7949_adc_spec[spi_get_device_id(spi)->driver_data];
indio_dev->num_channels = spec->num_channels;
ad7949_adc->resolution = spec->resolution;
ad7949_adc->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(ad7949_adc->vref)) {
dev_err(dev, "fail to request regulator\n");
return PTR_ERR(ad7949_adc->vref);
}
ret = regulator_enable(ad7949_adc->vref);
if (ret < 0) {
dev_err(dev, "fail to enable regulator\n");
return ret;
}
mutex_init(&ad7949_adc->lock);
ret = ad7949_spi_init(ad7949_adc);
if (ret) {
dev_err(dev, "enable to init this device: %d\n", ret);
goto err;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(dev, "fail to register iio device: %d\n", ret);
goto err;
}
return 0;
err:
mutex_destroy(&ad7949_adc->lock);
regulator_disable(ad7949_adc->vref);
return ret;
}
static int ad7949_spi_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mutex_destroy(&ad7949_adc->lock);
regulator_disable(ad7949_adc->vref);
return 0;
}
static const struct of_device_id ad7949_spi_of_id[] = {
{ .compatible = "adi,ad7949" },
{ .compatible = "adi,ad7682" },
{ .compatible = "adi,ad7689" },
{ }
};
MODULE_DEVICE_TABLE(of, ad7949_spi_of_id);
static const struct spi_device_id ad7949_spi_id[] = {
{ "ad7949", ID_AD7949 },
{ "ad7682", ID_AD7682 },
{ "ad7689", ID_AD7689 },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7949_spi_id);
static struct spi_driver ad7949_spi_driver = {
.driver = {
.name = "ad7949",
.of_match_table = ad7949_spi_of_id,
},
.probe = ad7949_spi_probe,
.remove = ad7949_spi_remove,
.id_table = ad7949_spi_id,
};
module_spi_driver(ad7949_spi_driver);
MODULE_AUTHOR("Charles-Antoine Couret <charles-antoine.couret@essensium.com>");
MODULE_DESCRIPTION("Analog Devices 14/16-bit 8-channel ADC driver");
MODULE_LICENSE("GPL v2");
......@@ -278,6 +278,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int sample, raw_sample;
unsigned int data_reg;
int ret = 0;
if (iio_buffer_enabled(indio_dev))
......@@ -305,7 +306,12 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
if (ret < 0)
goto out;
ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA,
if (sigma_delta->info->data_reg != 0)
data_reg = sigma_delta->info->data_reg;
else
data_reg = AD_SD_REG_DATA;
ret = ad_sd_read_reg(sigma_delta, data_reg,
DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
&raw_sample);
......@@ -392,6 +398,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned int reg_size;
unsigned int data_reg;
uint8_t data[16];
int ret;
......@@ -401,18 +408,23 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
indio_dev->channels[0].scan_type.shift;
reg_size = DIV_ROUND_UP(reg_size, 8);
if (sigma_delta->info->data_reg != 0)
data_reg = sigma_delta->info->data_reg;
else
data_reg = AD_SD_REG_DATA;
switch (reg_size) {
case 4:
case 2:
case 1:
ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
reg_size, &data[0]);
ret = ad_sd_read_reg_raw(sigma_delta, data_reg, reg_size,
&data[0]);
break;
case 3:
/* We store 24 bit samples in a 32 bit word. Keep the upper
* byte set to zero. */
ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
reg_size, &data[1]);
ret = ad_sd_read_reg_raw(sigma_delta, data_reg, reg_size,
&data[1]);
break;
}
......
......@@ -115,6 +115,7 @@
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
#define MAX_S5PV210_ADC_CHANNELS 10
/* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0)
......@@ -282,6 +283,16 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
.start_conv = exynos_adc_v1_start_conv,
};
static const struct exynos_adc_data exynos_adc_s5pv210_data = {
.num_channels = MAX_S5PV210_ADC_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.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 void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
unsigned long addr)
{
......@@ -478,6 +489,9 @@ static const struct of_device_id exynos_adc_match[] = {
}, {
.compatible = "samsung,s3c6410-adc",
.data = &exynos_adc_s3c64xx_data,
}, {
.compatible = "samsung,s5pv210-adc",
.data = &exynos_adc_s5pv210_data,
}, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
......
......@@ -250,6 +250,7 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
*val2 = chip->shunt_resistor_uohm;
return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
case IIO_CHAN_INFO_HARDWAREGAIN:
switch (chan->address) {
......@@ -262,6 +263,7 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
*val = chip->range_vbus == 32 ? 1 : 2;
return IIO_VAL_INT;
}
return -EINVAL;
}
return -EINVAL;
......
// SPDX-License-Identifier: GPL-2.0
/*
* iio/adc/max11100.c
* Maxim max11100 ADC Driver with IIO interface
*
* Copyright (C) 2016-17 Renesas Electronics Corporation
* Copyright (C) 2016-17 Jacopo Mondi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/kernel.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* iio/adc/max9611.c
*
......@@ -5,10 +6,6 @@
* 12-bit ADC interface.
*
* Copyright (C) 2017 Jacopo Mondi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
......
This diff is collapsed.
......@@ -423,6 +423,7 @@ struct adc5_channels {
enum vadc_scale_fn_type scale_fn_type;
};
/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */
#define ADC5_CHAN(_dname, _type, _mask, _pre, _scale) \
{ \
.datasheet_name = _dname, \
......@@ -443,63 +444,63 @@ struct adc5_channels {
_pre, _scale) \
static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
SCALE_HW_CALIB_PMIC_THERM)
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 1,
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 16,
[ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 8,
SCALE_HW_CALIB_DEFAULT)
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 1,
[ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 0,
SCALE_HW_CALIB_PM5_CHG_TEMP)
/* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 3,
[ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 6,
[ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 3,
SCALE_HW_CALIB_DEFAULT)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1,
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0,
SCALE_HW_CALIB_XOTHERM)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 1,
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 0,
SCALE_HW_CALIB_PM5_SMB_TEMP)
};
static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1,
[ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1,
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3,
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3,
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 3,
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 1,
SCALE_HW_CALIB_DEFAULT)
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1,
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
SCALE_HW_CALIB_PMIC_THERM)
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
[ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
[ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
[ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1,
[ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1,
[ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1,
[ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 0,
SCALE_HW_CALIB_THERM_100K_PULLUP)
};
......@@ -558,6 +559,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
return ret;
}
prop->prescale = ret;
} else {
prop->prescale =
adc->data->adc_chans[prop->channel].prescale_index;
}
ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Renesas R-Car GyroADC driver
*
* Copyright 2016 Marek Vasut <marek.vasut@gmail.com>
*
* 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.
*/
#include <linux/module.h>
......
......@@ -52,6 +52,9 @@
/* Timeout (ms) for the trylock of hardware spinlocks */
#define SC27XX_ADC_HWLOCK_TIMEOUT 5000
/* Timeout (ms) for ADC data conversion according to ADC datasheet */
#define SC27XX_ADC_RDY_TIMEOUT 100
/* Maximum ADC channel number */
#define SC27XX_ADC_CHANNEL_MAX 32
......@@ -223,7 +226,14 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
if (ret)
goto disable_adc;
wait_for_completion(&data->completion);
ret = wait_for_completion_timeout(&data->completion,
msecs_to_jiffies(SC27XX_ADC_RDY_TIMEOUT));
if (!ret) {
dev_err(data->dev, "read ADC data timeout\n");
ret = -ETIMEDOUT;
} else {
ret = 0;
}
disable_adc:
regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
......
......@@ -16,6 +16,7 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
......@@ -48,15 +49,19 @@
#define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status register offset
* @ccr: common control register offset
* @eoc1: adc1 end of conversion flag in @csr
* @eoc2: adc2 end of conversion flag in @csr
* @eoc3: adc3 end of conversion flag in @csr
*/
struct stm32_adc_common_regs {
u32 csr;
u32 ccr;
u32 eoc1_msk;
u32 eoc2_msk;
u32 eoc3_msk;
......@@ -85,6 +90,7 @@ struct stm32_adc_priv_cfg {
* @vref: regulator reference
* @cfg: compatible configuration data
* @common: common data for all ADC instances
* @ccr_bak: backup CCR in low power mode
*/
struct stm32_adc_priv {
int irq[STM32_ADC_MAX_ADCS];
......@@ -94,6 +100,7 @@ struct stm32_adc_priv {
struct regulator *vref;
const struct stm32_adc_priv_cfg *cfg;
struct stm32_adc_common common;
u32 ccr_bak;
};
static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
......@@ -265,6 +272,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
/* STM32F4 common registers definitions */
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
.eoc1_msk = STM32F4_EOC1,
.eoc2_msk = STM32F4_EOC2,
.eoc3_msk = STM32F4_EOC3,
......@@ -273,6 +281,7 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
/* STM32H7 common registers definitions */
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
.eoc1_msk = STM32H7_EOC_MST,
.eoc2_msk = STM32H7_EOC_SLV,
};
......@@ -379,6 +388,61 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
}
}
static int stm32_adc_core_hw_start(struct device *dev)
{
struct stm32_adc_common *common = dev_get_drvdata(dev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
int ret;
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed\n");
return ret;
}
if (priv->bclk) {
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(dev, "bus clk enable failed\n");
goto err_regulator_disable;
}
}
if (priv->aclk) {
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(dev, "adc clk enable failed\n");
goto err_bclk_disable;
}
}
writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr);
return 0;
err_bclk_disable:
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
err_regulator_disable:
regulator_disable(priv->vref);
return ret;
}
static void stm32_adc_core_hw_stop(struct device *dev)
{
struct stm32_adc_common *common = dev_get_drvdata(dev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
/* Backup CCR that may be lost (depends on power state to achieve) */
priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref);
}
static int stm32_adc_probe(struct platform_device *pdev)
{
struct stm32_adc_priv *priv;
......@@ -393,6 +457,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, &priv->common);
priv->cfg = (const struct stm32_adc_priv_cfg *)
of_match_device(dev->driver->of_match_table, dev)->data;
......@@ -410,67 +475,51 @@ static int stm32_adc_probe(struct platform_device *pdev)
return ret;
}
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(&pdev->dev, "vref enable failed\n");
return ret;
}
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
goto err_regulator_disable;
}
priv->common.vref_mv = ret / 1000;
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
priv->aclk = devm_clk_get(&pdev->dev, "adc");
if (IS_ERR(priv->aclk)) {
ret = PTR_ERR(priv->aclk);
if (ret == -ENOENT) {
priv->aclk = NULL;
} else {
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'adc' clock\n");
goto err_regulator_disable;
}
}
if (priv->aclk) {
ret = clk_prepare_enable(priv->aclk);
if (ret < 0) {
dev_err(&pdev->dev, "adc clk enable failed\n");
goto err_regulator_disable;
return ret;
}
priv->aclk = NULL;
}
priv->bclk = devm_clk_get(&pdev->dev, "bus");
if (IS_ERR(priv->bclk)) {
ret = PTR_ERR(priv->bclk);
if (ret == -ENOENT) {
priv->bclk = NULL;
} else {
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'bus' clock\n");
goto err_aclk_disable;
return ret;
}
priv->bclk = NULL;
}
if (priv->bclk) {
ret = clk_prepare_enable(priv->bclk);
if (ret < 0) {
dev_err(&pdev->dev, "adc clk enable failed\n");
goto err_aclk_disable;
}
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
ret = stm32_adc_core_hw_start(dev);
if (ret)
goto err_pm_stop;
ret = regulator_get_voltage(priv->vref);
if (ret < 0) {
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
goto err_hw_stop;
}
priv->common.vref_mv = ret / 1000;
dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv);
ret = priv->cfg->clk_sel(pdev, priv);
if (ret < 0)
goto err_bclk_disable;
goto err_hw_stop;
ret = stm32_adc_irq_probe(pdev, priv);
if (ret < 0)
goto err_bclk_disable;
platform_set_drvdata(pdev, &priv->common);
goto err_hw_stop;
ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
if (ret < 0) {
......@@ -478,21 +527,19 @@ static int stm32_adc_probe(struct platform_device *pdev)
goto err_irq_remove;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
err_irq_remove:
stm32_adc_irq_remove(pdev, priv);
err_bclk_disable:
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
err_aclk_disable:
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
err_regulator_disable:
regulator_disable(priv->vref);
err_hw_stop:
stm32_adc_core_hw_stop(dev);
err_pm_stop:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);
return ret;
}
......@@ -502,17 +549,39 @@ static int stm32_adc_remove(struct platform_device *pdev)
struct stm32_adc_common *common = platform_get_drvdata(pdev);
struct stm32_adc_priv *priv = to_stm32_adc_priv(common);
pm_runtime_get_sync(&pdev->dev);
of_platform_depopulate(&pdev->dev);
stm32_adc_irq_remove(pdev, priv);
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
if (priv->aclk)
clk_disable_unprepare(priv->aclk);
regulator_disable(priv->vref);
stm32_adc_core_hw_stop(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return 0;
}
#if defined(CONFIG_PM)
static int stm32_adc_core_runtime_suspend(struct device *dev)
{
stm32_adc_core_hw_stop(dev);
return 0;
}
static int stm32_adc_core_runtime_resume(struct device *dev)
{
return stm32_adc_core_hw_start(dev);
}
#endif
static const struct dev_pm_ops stm32_adc_core_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
stm32_adc_core_runtime_resume,
NULL)
};
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs,
.clk_sel = stm32f4_adc_clk_sel,
......@@ -552,6 +621,7 @@ static struct platform_driver stm32_adc_driver = {
.driver = {
.name = "stm32-adc-core",
.of_match_table = stm32_adc_of_match,
.pm = &stm32_adc_core_pm_ops,
},
};
module_platform_driver(stm32_adc_driver);
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
......@@ -6,16 +7,14 @@
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
* http://www.ti.com/lit/ds/symlink/adc122s021.pdf
* http://www.ti.com/lit/ds/symlink/adc124s021.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
struct adc128_configuration {
......@@ -135,10 +134,15 @@ static const struct iio_info adc128_info = {
static int adc128_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
unsigned int config;
struct adc128 *adc;
int config = spi_get_device_id(spi)->driver_data;
int ret;
if (dev_fwnode(&spi->dev))
config = (unsigned long) device_get_match_data(&spi->dev);
else
config = spi_get_device_id(spi)->driver_data;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
......@@ -186,23 +190,40 @@ static int adc128_remove(struct spi_device *spi)
static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc128s052", },
{ .compatible = "ti,adc122s021", },
{ .compatible = "ti,adc122s051", },
{ .compatible = "ti,adc122s101", },
{ .compatible = "ti,adc124s021", },
{ .compatible = "ti,adc124s051", },
{ .compatible = "ti,adc124s101", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0}, /* index into adc128_config */
{ "adc122s021", 1},
{ "adc124s021", 2},
{ "adc128s052", 0 }, /* index into adc128_config */
{ "adc122s021", 1 },
{ "adc122s051", 1 },
{ "adc122s101", 1 },
{ "adc124s021", 2 },
{ "adc124s051", 2 },
{ "adc124s101", 2 },
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id adc128_acpi_match[] = {
{ "AANT1280", 2 }, /* ADC124S021 compatible ACPI ID */
{ }
};
MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
#endif
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.of_match_table = of_match_ptr(adc128_of_match),
.acpi_match_table = ACPI_PTR(adc128_acpi_match),
},
.probe = adc128_probe,
.remove = adc128_remove,
......
......@@ -336,7 +336,7 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0,
scale1 = scale1 % pow_10(8 - i);
}
*val0 += res;
*val1 = scale1 * pow_10(exp);
*val1 = scale1 * pow_10(exp);
} else if (exp < 0) {
exp = abs(exp);
if (exp > 9) {
......
......@@ -462,43 +462,35 @@ static struct ssp_data *ssp_parse_dt(struct device *dev)
data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
if (data->mcu_ap_gpio < 0)
goto err_free_pd;
return NULL;
data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
if (data->ap_mcu_gpio < 0)
goto err_free_pd;
return NULL;
data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
if (data->mcu_reset_gpio < 0)
goto err_free_pd;
return NULL;
ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
"ap-mcu-gpios");
if (ret)
goto err_free_pd;
return NULL;
ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
if (ret)
goto err_ap_mcu;
return NULL;
match = of_match_node(ssp_of_match, node);
if (!match)
goto err_mcu_reset_gpio;
return NULL;
data->sensorhub_info = match->data;
dev_set_drvdata(dev, data);
return data;
err_mcu_reset_gpio:
devm_gpio_free(dev, data->mcu_reset_gpio);
err_ap_mcu:
devm_gpio_free(dev, data->ap_mcu_gpio);
err_free_pd:
devm_kfree(dev, data);
return NULL;
}
#else
static struct ssp_data *ssp_parse_dt(struct device *pdev)
......
......@@ -133,7 +133,7 @@ static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
if (sensor_settings->fs.fs_avl[i].num == 0)
goto st_sensors_match_odr_error;
return ret;
if (sensor_settings->fs.fs_avl[i].num == fs) {
*index_fs_avl = i;
......@@ -142,7 +142,6 @@ static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
}
}
st_sensors_match_odr_error:
return ret;
}
......
......@@ -104,7 +104,7 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p)
return IRQ_HANDLED;
/*
* If we are using egde IRQs, new samples arrived while processing
* If we are using edge IRQs, new samples arrived while processing
* the IRQ and those may be missed unless we pick them here, so poll
* again. If the sensor delivery frequency is very high, this thread
* turns into a polled loop handler.
......@@ -148,7 +148,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
dev_err(&indio_dev->dev,
"falling/low specified for IRQ "
"but hardware only support rising/high: "
"but hardware supports only rising/high: "
"will request rising/high\n");
if (irq_trig == IRQF_TRIGGER_FALLING)
irq_trig = IRQF_TRIGGER_RISING;
......
......@@ -366,6 +366,15 @@ config TI_DAC5571
If compiled as a module, it will be called ti-dac5571.
config TI_DAC7311
tristate "Texas Instruments 8/10/12-bit 1-channel DAC driver"
depends on SPI
help
Driver for the Texas Instruments
DAC7311, DAC6311, DAC5311.
If compiled as a module, it will be called ti-dac7311.
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
......
......@@ -40,4 +40,5 @@ obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
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_VF610_DAC) += vf610_dac.o
......@@ -19,6 +19,12 @@ static int ad5686_spi_write(struct ad5686_state *st,
u8 tx_len, *buf;
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) |
val);
buf = &st->data[0].d8[0];
tx_len = 2;
break;
case AD5683_REGMAP:
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5683_DATA(val));
......@@ -56,10 +62,18 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
u8 cmd = 0;
int ret;
if (st->chip_info->regmap_type == AD5686_REGMAP)
cmd = AD5686_CMD_READBACK_ENABLE;
else if (st->chip_info->regmap_type == AD5683_REGMAP)
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
return -ENOTSUPP;
case AD5683_REGMAP:
cmd = AD5686_CMD_READBACK_ENABLE_V2;
break;
case AD5686_REGMAP:
cmd = AD5686_CMD_READBACK_ENABLE;
break;
default:
return -EINVAL;
}
st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
AD5686_ADDR(addr));
......@@ -86,6 +100,7 @@ static int ad5686_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id ad5686_spi_id[] = {
{"ad5310r", ID_AD5310R},
{"ad5672r", ID_AD5672R},
{"ad5676", ID_AD5676},
{"ad5676r", ID_AD5676R},
......
......@@ -83,6 +83,10 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
shift = 9;
ref_bit_msk = AD5310_REF_BIT_MSK;
break;
case AD5683_REGMAP:
shift = 13;
ref_bit_msk = AD5683_REF_BIT_MSK;
......@@ -124,7 +128,8 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
*val = ret;
*val = (ret >> chan->scan_type.shift) &
GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = st->vref_mv;
......@@ -221,6 +226,7 @@ static struct iio_chan_spec name[] = { \
AD5868_CHANNEL(7, 7, bits, _shift), \
}
DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2);
DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6);
DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4);
DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0);
......@@ -232,6 +238,12 @@ DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2);
DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4);
static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
[ID_AD5310R] = {
.channels = ad5310r_channels,
.int_vref_mv = 2500,
.num_channels = 1,
.regmap_type = AD5310_REGMAP,
},
[ID_AD5311R] = {
.channels = ad5311r_channels,
.int_vref_mv = 2500,
......@@ -419,6 +431,11 @@ int ad5686_probe(struct device *dev,
indio_dev->num_channels = st->chip_info->num_channels;
switch (st->chip_info->regmap_type) {
case AD5310_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5310_REF_BIT_MSK;
st->use_internal_vref = !voltage_uv;
break;
case AD5683_REGMAP:
cmd = AD5686_CMD_CONTROL_REG;
ref_bit_msk = AD5683_REF_BIT_MSK;
......
......@@ -13,7 +13,10 @@
#include <linux/mutex.h>
#include <linux/kernel.h>
#define AD5310_CMD(x) ((x) << 12)
#define AD5683_DATA(x) ((x) << 4)
#define AD5686_ADDR(x) ((x) << 16)
#define AD5686_CMD(x) ((x) << 20)
......@@ -38,6 +41,8 @@
#define AD5686_CMD_CONTROL_REG 0x4
#define AD5686_CMD_READBACK_ENABLE_V2 0x5
#define AD5310_REF_BIT_MSK BIT(8)
#define AD5683_REF_BIT_MSK BIT(12)
#define AD5693_REF_BIT_MSK BIT(12)
......@@ -45,6 +50,7 @@
* ad5686_supported_device_ids:
*/
enum ad5686_supported_device_ids {
ID_AD5310R,
ID_AD5311R,
ID_AD5671R,
ID_AD5672R,
......@@ -72,6 +78,7 @@ enum ad5686_supported_device_ids {
};
enum ad5686_regmap_type {
AD5310_REGMAP,
AD5683_REGMAP,
AD5686_REGMAP,
AD5693_REGMAP
......
......@@ -74,11 +74,11 @@ static int dpot_dac_read_raw(struct iio_dev *indio_dev,
case IIO_VAL_INT:
/*
* Convert integer scale to fractional scale by
* setting the denominator (val2) to one...
* setting the denominator (val2) to one, and...
*/
*val2 = 1;
ret = IIO_VAL_FRACTIONAL;
/* ...and fall through. */
/* fall through */
case IIO_VAL_FRACTIONAL:
*val *= regulator_get_voltage(dac->vref) / 1000;
*val2 *= dac->max_ohms;
......
// SPDX-License-Identifier: GPL-2.0
/* ti-dac7311.c - Texas Instruments 8/10/12-bit 1-channel DAC driver
*
* Copyright (C) 2018 CMC NV
*
* http://www.ti.com/lit/ds/symlink/dac7311.pdf
*/
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
enum {
ID_DAC5311 = 0,
ID_DAC6311,
ID_DAC7311,
};
enum {
POWER_1KOHM_TO_GND = 0,
POWER_100KOHM_TO_GND,
POWER_TRI_STATE,
};
struct ti_dac_spec {
u8 resolution;
};
static const struct ti_dac_spec ti_dac_spec[] = {
[ID_DAC5311] = { .resolution = 8 },
[ID_DAC6311] = { .resolution = 10 },
[ID_DAC7311] = { .resolution = 12 },
};
/**
* struct ti_dac_chip - TI DAC chip
* @lock: protects write sequences
* @vref: regulator generating Vref
* @spi: SPI device to send data to the device
* @val: cached value
* @powerdown: whether the chip is powered down
* @powerdown_mode: selected by the user
* @resolution: resolution of the chip
* @buf: buffer for transfer data
*/
struct ti_dac_chip {
struct mutex lock;
struct regulator *vref;
struct spi_device *spi;
u16 val;
bool powerdown;
u8 powerdown_mode;
u8 resolution;
u8 buf[2] ____cacheline_aligned;
};
static u8 ti_dac_get_power(struct ti_dac_chip *ti_dac, bool powerdown)
{
if (powerdown)
return ti_dac->powerdown_mode + 1;
return 0;
}
static int ti_dac_cmd(struct ti_dac_chip *ti_dac, u8 power, u16 val)
{
u8 shift = 14 - ti_dac->resolution;
ti_dac->buf[0] = (val << shift) & 0xFF;
ti_dac->buf[1] = (power << 6) | (val >> (8 - shift));
return spi_write(ti_dac->spi, ti_dac->buf, 2);
}
static const char * const ti_dac_powerdown_modes[] = {
"1kohm_to_gnd",
"100kohm_to_gnd",
"three_state",
};
static int ti_dac_get_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
return ti_dac->powerdown_mode;
}
static int ti_dac_set_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int mode)
{
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
ti_dac->powerdown_mode = mode;
return 0;
}
static const struct iio_enum ti_dac_powerdown_mode = {
.items = ti_dac_powerdown_modes,
.num_items = ARRAY_SIZE(ti_dac_powerdown_modes),
.get = ti_dac_get_powerdown_mode,
.set = ti_dac_set_powerdown_mode,
};
static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
return sprintf(buf, "%d\n", ti_dac->powerdown);
}
static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
bool powerdown;
u8 power;
int ret;
ret = strtobool(buf, &powerdown);
if (ret)
return ret;
power = ti_dac_get_power(ti_dac, powerdown);
mutex_lock(&ti_dac->lock);
ret = ti_dac_cmd(ti_dac, power, 0);
if (!ret)
ti_dac->powerdown = powerdown;
mutex_unlock(&ti_dac->lock);
return ret ? ret : len;
}
static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = {
{
.name = "powerdown",
.read = ti_dac_read_powerdown,
.write = ti_dac_write_powerdown,
.shared = IIO_SHARED_BY_TYPE,
},
IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
IIO_ENUM_AVAILABLE("powerdown_mode", &ti_dac_powerdown_mode),
{ },
};
#define TI_DAC_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.channel = (chan), \
.output = true, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = ti_dac_ext_info, \
}
static const struct iio_chan_spec ti_dac_channels[] = {
TI_DAC_CHANNEL(0),
};
static int ti_dac_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
*val = ti_dac->val;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(ti_dac->vref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = ti_dac->resolution;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static int ti_dac_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
u8 power = ti_dac_get_power(ti_dac, ti_dac->powerdown);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (ti_dac->val == val)
return 0;
if (val >= (1 << ti_dac->resolution) || val < 0)
return -EINVAL;
if (ti_dac->powerdown)
return -EBUSY;
mutex_lock(&ti_dac->lock);
ret = ti_dac_cmd(ti_dac, power, val);
if (!ret)
ti_dac->val = val;
mutex_unlock(&ti_dac->lock);
break;
default:
ret = -EINVAL;
}
return ret;
}
static int ti_dac_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, long mask)
{
return IIO_VAL_INT;
}
static const struct iio_info ti_dac_info = {
.read_raw = ti_dac_read_raw,
.write_raw = ti_dac_write_raw,
.write_raw_get_fmt = ti_dac_write_raw_get_fmt,
};
static int ti_dac_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
const struct ti_dac_spec *spec;
struct ti_dac_chip *ti_dac;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*ti_dac));
if (!indio_dev) {
dev_err(dev, "can not allocate iio device\n");
return -ENOMEM;
}
spi->mode = SPI_MODE_1;
spi->bits_per_word = 16;
spi_setup(spi);
indio_dev->dev.parent = dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->info = &ti_dac_info;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ti_dac_channels;
spi_set_drvdata(spi, indio_dev);
ti_dac = iio_priv(indio_dev);
ti_dac->powerdown = false;
ti_dac->spi = spi;
spec = &ti_dac_spec[spi_get_device_id(spi)->driver_data];
indio_dev->num_channels = 1;
ti_dac->resolution = spec->resolution;
ti_dac->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(ti_dac->vref)) {
dev_err(dev, "error to get regulator\n");
return PTR_ERR(ti_dac->vref);
}
ret = regulator_enable(ti_dac->vref);
if (ret < 0) {
dev_err(dev, "can not enable regulator\n");
return ret;
}
mutex_init(&ti_dac->lock);
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(dev, "fail to register iio device: %d\n", ret);
goto err;
}
return 0;
err:
mutex_destroy(&ti_dac->lock);
regulator_disable(ti_dac->vref);
return ret;
}
static int ti_dac_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mutex_destroy(&ti_dac->lock);
regulator_disable(ti_dac->vref);
return 0;
}
static const struct of_device_id ti_dac_of_id[] = {
{ .compatible = "ti,dac5311" },
{ .compatible = "ti,dac6311" },
{ .compatible = "ti,dac7311" },
{ }
};
MODULE_DEVICE_TABLE(of, ti_dac_of_id);
static const struct spi_device_id ti_dac_spi_id[] = {
{ "dac5311", ID_DAC5311 },
{ "dac6311", ID_DAC6311 },
{ "dac7311", ID_DAC7311 },
{ }
};
MODULE_DEVICE_TABLE(spi, ti_dac_spi_id);
static struct spi_driver ti_dac_driver = {
.driver = {
.name = "ti-dac7311",
.of_match_table = ti_dac_of_id,
},
.probe = ti_dac_probe,
.remove = ti_dac_remove,
.id_table = ti_dac_spi_id,
};
module_spi_driver(ti_dac_driver);
MODULE_AUTHOR("Charles-Antoine Couret <charles-antoine.couret@essensium.com>");
MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1-channel DAC driver");
MODULE_LICENSE("GPL v2");
......@@ -6,6 +6,5 @@ extern const struct regmap_config bmi160_regmap_config;
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
void bmi160_core_remove(struct device *dev);
#endif /* BMI160_H_ */
......@@ -542,10 +542,12 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi)
return 0;
}
static void bmi160_chip_uninit(struct bmi160_data *data)
static void bmi160_chip_uninit(void *data)
{
bmi160_set_mode(data, BMI160_GYRO, false);
bmi160_set_mode(data, BMI160_ACCEL, false);
struct bmi160_data *bmi_data = data;
bmi160_set_mode(bmi_data, BMI160_GYRO, false);
bmi160_set_mode(bmi_data, BMI160_ACCEL, false);
}
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
......@@ -567,6 +569,10 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(dev, bmi160_chip_uninit, data);
if (ret < 0)
return ret;
if (!name && ACPI_HANDLE(dev))
name = bmi160_match_acpi_device(dev);
......@@ -577,35 +583,19 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmi160_info;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bmi160_trigger_handler, NULL);
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
bmi160_trigger_handler, NULL);
if (ret < 0)
goto uninit;
return ret;
ret = iio_device_register(indio_dev);
ret = devm_iio_device_register(dev, indio_dev);
if (ret < 0)
goto buffer_cleanup;
return ret;
return 0;
buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
uninit:
bmi160_chip_uninit(data);
return ret;
}
EXPORT_SYMBOL_GPL(bmi160_core_probe);
void bmi160_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmi160_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
bmi160_chip_uninit(data);
}
EXPORT_SYMBOL_GPL(bmi160_core_remove);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
MODULE_DESCRIPTION("Bosch BMI160 driver");
MODULE_LICENSE("GPL v2");
......@@ -38,13 +38,6 @@ static int bmi160_i2c_probe(struct i2c_client *client,
return bmi160_core_probe(&client->dev, regmap, name, false);
}
static int bmi160_i2c_remove(struct i2c_client *client)
{
bmi160_core_remove(&client->dev);
return 0;
}
static const struct i2c_device_id bmi160_i2c_id[] = {
{"bmi160", 0},
{}
......@@ -72,7 +65,6 @@ static struct i2c_driver bmi160_i2c_driver = {
.of_match_table = of_match_ptr(bmi160_of_match),
},
.probe = bmi160_i2c_probe,
.remove = bmi160_i2c_remove,
.id_table = bmi160_i2c_id,
};
module_i2c_driver(bmi160_i2c_driver);
......
......@@ -29,13 +29,6 @@ static int bmi160_spi_probe(struct spi_device *spi)
return bmi160_core_probe(&spi->dev, regmap, id->name, true);
}
static int bmi160_spi_remove(struct spi_device *spi)
{
bmi160_core_remove(&spi->dev);
return 0;
}
static const struct spi_device_id bmi160_spi_id[] = {
{"bmi160", 0},
{}
......@@ -58,7 +51,6 @@ MODULE_DEVICE_TABLE(of, bmi160_of_match);
static struct spi_driver bmi160_spi_driver = {
.probe = bmi160_spi_probe,
.remove = bmi160_spi_remove,
.id_table = bmi160_spi_id,
.driver = {
.acpi_match_table = ACPI_PTR(bmi160_acpi_match),
......
st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o
st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \
st_lsm6dsx_shub.o
obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
......
......@@ -43,6 +43,24 @@ enum st_lsm6dsx_hw_id {
* ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
#define ST_LSM6DSX_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask))
#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \
{ \
.type = chan_type, \
.address = addr, \
.modified = 1, \
.channel2 = mod, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = scan_idx, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
struct st_lsm6dsx_reg {
u8 addr;
u8 mask;
......@@ -50,6 +68,28 @@ struct st_lsm6dsx_reg {
struct st_lsm6dsx_hw;
struct st_lsm6dsx_odr {
u16 hz;
u8 val;
};
#define ST_LSM6DSX_ODR_LIST_SIZE 6
struct st_lsm6dsx_odr_table_entry {
struct st_lsm6dsx_reg reg;
struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
};
struct st_lsm6dsx_fs {
u32 gain;
u8 val;
};
#define ST_LSM6DSX_FS_LIST_SIZE 4
struct st_lsm6dsx_fs_table_entry {
struct st_lsm6dsx_reg reg;
struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];
};
/**
* struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
* @read_fifo: Read FIFO callback.
......@@ -84,6 +124,70 @@ struct st_lsm6dsx_hw_ts_settings {
struct st_lsm6dsx_reg decimator;
};
/**
* struct st_lsm6dsx_shub_settings - ST IMU hw i2c controller settings
* @page_mux: register page mux info (addr + mask).
* @master_en: master config register info (addr + mask).
* @pullup_en: i2c controller pull-up register info (addr + mask).
* @aux_sens: aux sensor register info (addr + mask).
* @wr_once: write_once register info (addr + mask).
* @shub_out: sensor hub first output register info.
* @slv0_addr: slave0 address in secondary page.
* @dw_slv0_addr: slave0 write register address in secondary page.
* @batch_en: Enable/disable FIFO batching.
*/
struct st_lsm6dsx_shub_settings {
struct st_lsm6dsx_reg page_mux;
struct st_lsm6dsx_reg master_en;
struct st_lsm6dsx_reg pullup_en;
struct st_lsm6dsx_reg aux_sens;
struct st_lsm6dsx_reg wr_once;
u8 shub_out;
u8 slv0_addr;
u8 dw_slv0_addr;
u8 batch_en;
};
enum st_lsm6dsx_ext_sensor_id {
ST_LSM6DSX_ID_MAGN,
};
/**
* struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings
* @i2c_addr: I2c slave address list.
* @wai: Wai address info.
* @id: external sensor id.
* @odr: Output data rate of the sensor [Hz].
* @gain: Configured sensor sensitivity.
* @temp_comp: Temperature compensation register info (addr + mask).
* @pwr_table: Power on register info (addr + mask).
* @off_canc: Offset cancellation register info (addr + mask).
* @bdu: Block data update register info (addr + mask).
* @out: Output register info.
*/
struct st_lsm6dsx_ext_dev_settings {
u8 i2c_addr[2];
struct {
u8 addr;
u8 val;
} wai;
enum st_lsm6dsx_ext_sensor_id id;
struct st_lsm6dsx_odr_table_entry odr_table;
struct st_lsm6dsx_fs_table_entry fs_table;
struct st_lsm6dsx_reg temp_comp;
struct {
struct st_lsm6dsx_reg reg;
u8 off_val;
u8 on_val;
} pwr_table;
struct st_lsm6dsx_reg off_canc;
struct st_lsm6dsx_reg bdu;
struct {
u8 addr;
u8 len;
} out;
};
/**
* struct st_lsm6dsx_settings - ST IMU sensor settings
* @wai: Sensor WhoAmI default value.
......@@ -93,6 +197,7 @@ struct st_lsm6dsx_hw_ts_settings {
* @batch: List of FIFO batching register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
* @ts_settings: Hw timer related settings.
* @shub_settings: i2c controller related settings.
*/
struct st_lsm6dsx_settings {
u8 wai;
......@@ -102,11 +207,15 @@ struct st_lsm6dsx_settings {
struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
struct st_lsm6dsx_hw_ts_settings ts_settings;
struct st_lsm6dsx_shub_settings shub_settings;
};
enum st_lsm6dsx_sensor_id {
ST_LSM6DSX_ID_ACC,
ST_LSM6DSX_ID_GYRO,
ST_LSM6DSX_ID_ACC,
ST_LSM6DSX_ID_EXT0,
ST_LSM6DSX_ID_EXT1,
ST_LSM6DSX_ID_EXT2,
ST_LSM6DSX_ID_MAX,
};
......@@ -126,6 +235,7 @@ enum st_lsm6dsx_fifo_mode {
* @sip: Number of samples in a given pattern.
* @decimator: FIFO decimation factor.
* @ts_ref: Sensor timestamp reference for hw one.
* @ext_info: Sensor settings if it is connected to i2c controller
*/
struct st_lsm6dsx_sensor {
char name[32];
......@@ -139,6 +249,11 @@ struct st_lsm6dsx_sensor {
u8 sip;
u8 decimator;
s64 ts_ref;
struct {
const struct st_lsm6dsx_ext_dev_settings *settings;
u8 addr;
} ext_info;
};
/**
......@@ -148,6 +263,7 @@ struct st_lsm6dsx_sensor {
* @irq: Device interrupt line (I2C or SPI).
* @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
* @conf_lock: Mutex to prevent concurrent FIFO configuration update.
* @page_lock: Mutex to prevent concurrent memory page configuration.
* @fifo_mode: FIFO operating mode supported by the device.
* @enable_mask: Enabled sensor bitmask.
* @ts_sip: Total number of timestamp samples in a given pattern.
......@@ -163,6 +279,7 @@ struct st_lsm6dsx_hw {
struct mutex fifo_lock;
struct mutex conf_lock;
struct mutex page_lock;
enum st_lsm6dsx_fifo_mode fifo_mode;
u8 enable_mask;
......@@ -176,13 +293,15 @@ struct st_lsm6dsx_hw {
const struct st_lsm6dsx_settings *settings;
};
static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
struct regmap *regmap);
int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
bool enable);
int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val);
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
u16 watermark);
int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
......@@ -191,5 +310,47 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val);
int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);
int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);
static inline int
st_lsm6dsx_update_bits_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,
unsigned int mask, unsigned int val)
{
int err;
mutex_lock(&hw->page_lock);
err = regmap_update_bits(hw->regmap, addr, mask, val);
mutex_unlock(&hw->page_lock);
return err;
}
static inline int
st_lsm6dsx_read_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,
void *val, unsigned int len)
{
int err;
mutex_lock(&hw->page_lock);
err = regmap_bulk_read(hw->regmap, addr, val, len);
mutex_unlock(&hw->page_lock);
return err;
}
static inline int
st_lsm6dsx_write_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,
unsigned int val)
{
int err;
mutex_lock(&hw->page_lock);
err = regmap_write(hw->regmap, addr, val);
mutex_unlock(&hw->page_lock);
return err;
}
#endif /* ST_LSM6DSX_H */
......@@ -68,6 +68,9 @@ enum st_lsm6dsx_fifo_tag {
ST_LSM6DSX_GYRO_TAG = 0x01,
ST_LSM6DSX_ACC_TAG = 0x02,
ST_LSM6DSX_TS_TAG = 0x04,
ST_LSM6DSX_EXT0_TAG = 0x0f,
ST_LSM6DSX_EXT1_TAG = 0x10,
ST_LSM6DSX_EXT2_TAG = 0x11,
};
static const
......@@ -102,6 +105,9 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
*max_odr = 0, *min_odr = ~0;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
if (!hw->iio_devs[i])
continue;
sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(sensor->id)))
......@@ -125,6 +131,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
const struct st_lsm6dsx_reg *dec_reg;
if (!hw->iio_devs[i])
continue;
sensor = iio_priv(hw->iio_devs[i]);
/* update fifo decimators and sample in pattern */
if (hw->enable_mask & BIT(sensor->id)) {
......@@ -142,8 +151,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
if (dec_reg->addr) {
int val = ST_LSM6DSX_SHIFT_VAL(data, dec_reg->mask);
err = regmap_update_bits(hw->regmap, dec_reg->addr,
dec_reg->mask, val);
err = st_lsm6dsx_update_bits_locked(hw, dec_reg->addr,
dec_reg->mask,
val);
if (err < 0)
return err;
}
......@@ -162,8 +172,8 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
int val, ts_dec = !!hw->ts_sip;
val = ST_LSM6DSX_SHIFT_VAL(ts_dec, ts_dec_reg->mask);
err = regmap_update_bits(hw->regmap, ts_dec_reg->addr,
ts_dec_reg->mask, val);
err = st_lsm6dsx_update_bits_locked(hw, ts_dec_reg->addr,
ts_dec_reg->mask, val);
}
return err;
}
......@@ -171,12 +181,12 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode)
{
unsigned int data;
int err;
err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_MODE_MASK,
FIELD_PREP(ST_LSM6DSX_FIFO_MODE_MASK,
fifo_mode));
data = FIELD_PREP(ST_LSM6DSX_FIFO_MODE_MASK, fifo_mode);
err = st_lsm6dsx_update_bits_locked(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_MODE_MASK, data);
if (err < 0)
return err;
......@@ -207,15 +217,15 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
data = 0;
}
val = ST_LSM6DSX_SHIFT_VAL(data, batch_reg->mask);
return regmap_update_bits(hw->regmap, batch_reg->addr,
batch_reg->mask, val);
return st_lsm6dsx_update_bits_locked(hw, batch_reg->addr,
batch_reg->mask, val);
} else {
data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
return regmap_update_bits(hw->regmap,
ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_ODR_MASK,
FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
data));
return st_lsm6dsx_update_bits_locked(hw,
ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_ODR_MASK,
FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
data));
}
}
......@@ -231,6 +241,9 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
return 0;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
if (!hw->iio_devs[i])
continue;
cur_sensor = iio_priv(hw->iio_devs[i]);
if (!(hw->enable_mask & BIT(cur_sensor->id)))
......@@ -246,19 +259,23 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
fifo_watermark = (fifo_watermark / hw->sip) * hw->sip;
fifo_watermark = fifo_watermark * hw->settings->fifo_ops.th_wl;
mutex_lock(&hw->page_lock);
err = regmap_read(hw->regmap, hw->settings->fifo_ops.fifo_th.addr + 1,
&data);
if (err < 0)
return err;
goto out;
fifo_th_mask = hw->settings->fifo_ops.fifo_th.mask;
fifo_watermark = ((data << 8) & ~fifo_th_mask) |
(fifo_watermark & fifo_th_mask);
wdata = cpu_to_le16(fifo_watermark);
return regmap_bulk_write(hw->regmap,
hw->settings->fifo_ops.fifo_th.addr,
&wdata, sizeof(wdata));
err = regmap_bulk_write(hw->regmap,
hw->settings->fifo_ops.fifo_th.addr,
&wdata, sizeof(wdata));
out:
mutex_unlock(&hw->page_lock);
return err;
}
static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
......@@ -267,12 +284,15 @@ static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
int i, err;
/* reset hw ts counter */
err = regmap_write(hw->regmap, ST_LSM6DSX_REG_TS_RESET_ADDR,
ST_LSM6DSX_TS_RESET_VAL);
err = st_lsm6dsx_write_locked(hw, ST_LSM6DSX_REG_TS_RESET_ADDR,
ST_LSM6DSX_TS_RESET_VAL);
if (err < 0)
return err;
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
if (!hw->iio_devs[i])
continue;
sensor = iio_priv(hw->iio_devs[i]);
/*
* store enable buffer timestamp as reference for
......@@ -297,8 +317,8 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
while (read_len < data_len) {
word_len = min_t(unsigned int, data_len - read_len,
max_word_len);
err = regmap_bulk_read(hw->regmap, addr, data + read_len,
word_len);
err = st_lsm6dsx_read_locked(hw, addr, data + read_len,
word_len);
if (err < 0)
return err;
read_len += word_len;
......@@ -328,9 +348,9 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
__le16 fifo_status;
s64 ts = 0;
err = regmap_bulk_read(hw->regmap,
hw->settings->fifo_ops.fifo_diff.addr,
&fifo_status, sizeof(fifo_status));
err = st_lsm6dsx_read_locked(hw,
hw->settings->fifo_ops.fifo_diff.addr,
&fifo_status, sizeof(fifo_status));
if (err < 0) {
dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
err);
......@@ -436,6 +456,55 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
return read_len;
}
static int
st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
u8 *data, s64 ts)
{
struct st_lsm6dsx_sensor *sensor;
struct iio_dev *iio_dev;
/*
* EXT_TAG are managed in FIFO fashion so ST_LSM6DSX_EXT0_TAG
* corresponds to the first enabled channel, ST_LSM6DSX_EXT1_TAG
* to the second one and ST_LSM6DSX_EXT2_TAG to the last enabled
* channel
*/
switch (tag) {
case ST_LSM6DSX_GYRO_TAG:
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_GYRO];
break;
case ST_LSM6DSX_ACC_TAG:
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_ACC];
break;
case ST_LSM6DSX_EXT0_TAG:
if (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT0))
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT0];
else if (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT1))
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT1];
else
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
break;
case ST_LSM6DSX_EXT1_TAG:
if ((hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT0)) &&
(hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT1)))
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT1];
else
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
break;
case ST_LSM6DSX_EXT2_TAG:
iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
break;
default:
return -EINVAL;
}
sensor = iio_priv(iio_dev);
iio_push_to_buffers_with_timestamp(iio_dev, data,
ts + sensor->ts_ref);
return 0;
}
/**
* st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
......@@ -455,9 +524,9 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
__le16 fifo_status;
s64 ts = 0;
err = regmap_bulk_read(hw->regmap,
hw->settings->fifo_ops.fifo_diff.addr,
&fifo_status, sizeof(fifo_status));
err = st_lsm6dsx_read_locked(hw,
hw->settings->fifo_ops.fifo_diff.addr,
&fifo_status, sizeof(fifo_status));
if (err < 0) {
dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
err);
......@@ -491,8 +560,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
ST_LSM6DSX_SAMPLE_SIZE);
tag = hw->buff[i] >> 3;
switch (tag) {
case ST_LSM6DSX_TS_TAG:
if (tag == ST_LSM6DSX_TS_TAG) {
/*
* hw timestamp is 4B long and it is stored
* in FIFO according to this schema:
......@@ -509,19 +577,9 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
if (!reset_ts && ts >= 0xffff0000)
reset_ts = true;
ts *= ST_LSM6DSX_TS_SENSITIVITY;
break;
case ST_LSM6DSX_GYRO_TAG:
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_GYRO],
iio_buff, gyro_sensor->ts_ref + ts);
break;
case ST_LSM6DSX_ACC_TAG:
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_ACC],
iio_buff, acc_sensor->ts_ref + ts);
break;
default:
break;
} else {
st_lsm6dsx_push_tagged_data(hw, tag, iio_buff,
ts);
}
}
}
......@@ -562,19 +620,21 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
goto out;
}
if (enable) {
err = st_lsm6dsx_sensor_enable(sensor);
if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
sensor->id == ST_LSM6DSX_ID_EXT1 ||
sensor->id == ST_LSM6DSX_ID_EXT2) {
err = st_lsm6dsx_shub_set_enable(sensor, enable);
if (err < 0)
goto out;
} else {
err = st_lsm6dsx_sensor_disable(sensor);
err = st_lsm6dsx_sensor_set_enable(sensor, enable);
if (err < 0)
goto out;
}
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
goto out;
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
goto out;
}
err = st_lsm6dsx_update_decimators(hw);
if (err < 0)
......@@ -690,6 +750,9 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
}
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
if (!hw->iio_devs[i])
continue;
buffer = devm_iio_kfifo_allocate(hw->dev);
if (!buffer)
return -ENOMEM;
......
This diff is collapsed.
......@@ -1671,6 +1671,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
if (ret < 0)
return ret;
if (!indio_dev->info)
return -EINVAL;
/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
......
......@@ -460,6 +460,19 @@ config VCNL4000
To compile this driver as a module, choose M here: the
module will be called vcnl4000.
config VCNL4035
tristate "VCNL4035 combined ALS and proximity sensor"
select IIO_TRIGGERED_BUFFER
select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VCNL4035,
combined ambient light (ALS) and proximity sensor. Currently only ALS
function is available.
To compile this driver as a module, choose M here: the
module will be called vcnl4035.
config VEML6070
tristate "VEML6070 UV A light sensor"
depends on I2C
......
......@@ -45,6 +45,7 @@ obj-$(CONFIG_TSL2772) += tsl2772.o
obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VCNL4035) += vcnl4035.o
obj-$(CONFIG_VEML6070) += veml6070.o
obj-$(CONFIG_VL6180) += vl6180.o
obj-$(CONFIG_ZOPT2201) += zopt2201.o
This diff is collapsed.
......@@ -175,4 +175,33 @@ config SENSORS_HMC5843_SPI
- hmc5843_core (core functions)
- hmc5843_spi (support for HMC5983)
config SENSORS_RM3100
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config SENSORS_RM3100_I2C
tristate "PNI RM3100 3-Axis Magnetometer (I2C)"
depends on I2C
select SENSORS_RM3100
select REGMAP_I2C
help
Say Y here to add support for the PNI RM3100 3-Axis Magnetometer.
This driver can also be compiled as a module.
To compile this driver as a module, choose M here: the module
will be called rm3100-i2c.
config SENSORS_RM3100_SPI
tristate "PNI RM3100 3-Axis Magnetometer (SPI)"
depends on SPI_MASTER
select SENSORS_RM3100
select REGMAP_SPI
help
Say Y here to add support for the PNI RM3100 3-Axis Magnetometer.
This driver can also be compiled as a module.
To compile this driver as a module, choose M here: the module
will be called rm3100-spi.
endmenu
......@@ -24,3 +24,7 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o
obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o
obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
obj-$(CONFIG_SENSORS_RM3100) += rm3100-core.o
obj-$(CONFIG_SENSORS_RM3100_I2C) += rm3100-i2c.o
obj-$(CONFIG_SENSORS_RM3100_SPI) += rm3100-spi.o
......@@ -790,6 +790,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
{"INVN6500", AK8963},
{"AK009911", AK09911},
{"AK09911", AK09911},
{"AKM9911", AK09911},
{"AK09912", AK09912},
{ },
};
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Support for PNI RM3100 3-axis geomagnetic sensor on a i2c bus.
*
* Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
*
* i2c slave address: 0x20 + SA1 << 1 + SA0.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include "rm3100.h"
static const struct regmap_config rm3100_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.rd_table = &rm3100_readable_table,
.wr_table = &rm3100_writable_table,
.volatile_table = &rm3100_volatile_table,
.cache_type = REGCACHE_RBTREE,
};
static int rm3100_probe(struct i2c_client *client)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &rm3100_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return rm3100_common_probe(&client->dev, regmap, client->irq);
}
static const struct of_device_id rm3100_dt_match[] = {
{ .compatible = "pni,rm3100", },
{ }
};
MODULE_DEVICE_TABLE(of, rm3100_dt_match);
static struct i2c_driver rm3100_driver = {
.driver = {
.name = "rm3100-i2c",
.of_match_table = rm3100_dt_match,
},
.probe_new = rm3100_probe,
};
module_i2c_driver(rm3100_driver);
MODULE_AUTHOR("Song Qiang <songqiang1304521@gmail.com>");
MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
*/
#ifndef RM3100_CORE_H
#define RM3100_CORE_H
#include <linux/regmap.h>
extern const struct regmap_access_table rm3100_readable_table;
extern const struct regmap_access_table rm3100_writable_table;
extern const struct regmap_access_table rm3100_volatile_table;
int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq);
#endif /* RM3100_CORE_H */
......@@ -20,6 +20,7 @@
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn"
#define LIS2MDL_MAGN_DEV_NAME "lis2mdl"
#define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn"
int st_magn_common_probe(struct iio_dev *indio_dev);
void st_magn_common_remove(struct iio_dev *indio_dev);
......
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.
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