Commit 9f827d80 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

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

Jonathan writes:

First round of new driver, new functionality and cleanups for IIO in the 4.4 cycle

New device support
* APDS9960 ALS + proximity driver
* bmg160 SPI devices.
* HDC100x humidity sensors
* Holt HI-8435 threshold detector
* mma8453Q accelerometer added to the mma8452 driver
* mma86452FC and mma8653FC accelerometers added to the mma8452 driver
* mxc4005 accelerometer
* PulsedLight LIDAR
* SensorTech VZ89x volatile organic compound sensor
* UPISEMI uS5182d ALS and proximity sensors

New core functionality
* triggered events - use triggers to check for changes in threshold type
  detectors on devices with out interrupt support.  First user is the holt
  comparator.
* chemical concentration and resistance channel types.

New driver functionality
* vf610
  - buffer support.
  - followup coccinelle warning fix.

Core rework
* buffers
  - break out callback buffer to own module.
  - move buffer implementations to a new subdirectory
* percolate the error code form iio_event_getfd out to userspace
  rather than giving a missleading error later on.

Cleanups
* adddac drivers
  - use BIT macro where appropriate.
* meter drivers
  - use BIT macro where appropriate.

* ad7303
 - add an OF match table to line up with the binding docs.
* adc128s052
  - add an OF match table to line up with the binding docs.
* adf4350
  - add an OF match table to line up with the binding docs
* as3935
  - add an OF match table to line up with the binding docs.
* berlin2-adc
  - use GENMASK and BIT for masks
  - prevent attempting to sample multiple channels at once by moving a
    mutex scop
  - coding style cleanups
* bmg150_magn
  - kconfig sort order was wrong - fix it.
* bmg160
  - use i2c regmap and drop all uses of i2c_client
  - separate i2c and core driver
* cc10001_adc
  - kconfig sort order was wrong - fix it.
* evgen (dummy driver helper module)
  - move interrupt generation to irq_work to reduce differences between
    the dummy driver and real hardware drivers.
* hmc5843
  - set the name dynamically rather than to a fixed value for one of the
    suported parts.
  - export module alias information to allow autoprobing of module.
* lpc32xx
  - on failure to get resource or irq return -ENXIO as uppose to -EBUSY
* max1027
  - set .of_match_table to actually allow OF style matching.
* max5821
  - add MODULE_DEVICE_TABLE for OF table.
* mma8452
  - refactor to separate out chip specific data.
  - add freefall / motion interrupt source for devices that do their
    interrupts slightly differently.
  - update copywrite notice.
  - leave naming of events directory in sysfs to the core
* mcp320x
  - set .of_match_table so that it can be use for OF style matching.
* mlx90614
  - Implement filter configuration (note the datasheet changed as a result
    of the driver reviews to include the values we needed ;)
* opt3001
  - drop .owner field as assigned by platform driver core.
* si7020
  - replace a bitmask on the humidity values with a more correct range
    check.
* stk310
  - improved error handling.
  - use BIT macro where appropriate and use the resulting defines
    instead of magic numbers in the code.
  - fix indentation
* st-sensors
  - add debugfs register read hook
* tsl4531
  - fix error handling in check_id
* twl6030
  - fix module autoload for OF
* iio-trig-sysfs
  - document add and remove attribute
* trigger in staging
  - code alignment fixes.
  - braces on both branches of if statement if needed for one.
* xilinx-xadc
  - push interrupts into hardirq context as there isn't much in them
    any more and it avoids breaking PREEMPT_RT builds due to the use
    of a spinlock between the hardirq and the thread.

Tools
* event-monitor
  - report unsupported events.  We keep expanding what can come from drivers
    so give a helpful error if one turns up in an out of date userspace
    program.
* generic-buffer
  - helpful message about needing to enable a channel to start the buffer.
parents 99207b80 1d2f1e08
......@@ -581,6 +581,7 @@ What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_voltageY_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_voltageY_thresh_either_en
What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
KernelVersion: 2.6.37
......@@ -1459,3 +1460,22 @@ Description:
measurements and return the average value as output data. Each
value resulted from <type>[_name]_oversampling_ratio measurements
is considered as one sample for <type>[_name]_sampling_frequency.
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_co2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_co2_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_voc_raw
What: /sys/bus/iio/devices/iio:deviceX/in_concentrationX_voc_raw
KernelVersion: 4.3
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) percentage reading of a substance.
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw
What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw
KernelVersion: 4.3
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) resistance reading that can be processed
into an ohm value.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_sensing_mode
Date: August 2015
KernelVersion: 4.2.0
Contact: source@cogentembedded.com
Description:
Program sensor type for threshold detector inputs.
Could be either "GND-Open" or "Supply-Open" mode. Y is a
threshold detector input channel. Channels 0..7, 8..15, 16..23
and 24..31 has common sensor types.
What: /sys/bus/iio/devices/iio:deviceX/events/in_voltageY_thresh_falling_value
Date: August 2015
KernelVersion: 4.2.0
Contact: source@cogentembedded.com
Description:
Channel Y low voltage threshold. If sensor input voltage goes lower then
this value then the threshold falling event is pushed.
Depending on in_voltageY_sensing_mode the low voltage threshold
is separately set for "GND-Open" and "Supply-Open" modes.
Channels 0..31 have common low threshold values, but could have different
sensing_modes.
The low voltage threshold range is between 2..21V.
Hysteresis between low and high thresholds can not be lower then 2 and
can not be odd.
If falling threshold results hysteresis to odd value then rising
threshold is automatically subtracted by one.
What: /sys/bus/iio/devices/iio:deviceX/events/in_voltageY_thresh_rising_value
Date: August 2015
KernelVersion: 4.2.0
Contact: source@cogentembedded.com
Description:
Channel Y high voltage threshold. If sensor input voltage goes higher then
this value then the threshold rising event is pushed.
Depending on in_voltageY_sensing_mode the high voltage threshold
is separately set for "GND-Open" and "Supply-Open" modes.
Channels 0..31 have common high threshold values, but could have different
sensing_modes.
The high voltage threshold range is between 3..22V.
Hysteresis between low and high thresholds can not be lower then 2 and
can not be odd.
If rising threshold results hysteresis to odd value then falling
threshold is automatically appended by one.
What: /sys/bus/iio/devices/iio:deviceX/in_concentration_VOC_short_raw
Date: September 2015
KernelVersion: 4.3
Contact: Matt Ranostay <mranostay@gmail.com>
Description:
Get the raw calibration VOC value from the sensor.
This value has little application outside of calibration.
What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw
What: /sys/bus/iio/devices/iio:deviceX/out_current_heater_raw_available
KernelVersion: 4.3
Contact: linux-iio@vger.kernel.org
Description:
Controls the heater device within the humidity sensor to get
rid of excess condensation.
Valid control values are 0 = OFF, and 1 = ON.
......@@ -18,3 +18,25 @@ Description:
trigger. In order to associate the trigger with an IIO device
one should write this name string to
/sys/bus/iio/devices/iio:deviceY/trigger/current_trigger.
What: /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger
KernelVersion: 2.6.39
Contact: linux-iio@vger.kernel.org
Description:
This attribute is provided by the iio-trig-sysfs stand-alone
driver and it is used to activate the creation of a new trigger.
In order to achieve this, one should write a positive integer
into the associated file, which will serve as the id of the
trigger. If the trigger with the specified id is already present
in the system, an invalid argument message will be returned.
What: /sys/bus/iio/devices/iio_sysfs_trigger/remove_trigger
KernelVersion: 2.6.39
Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to unregister and delete a previously
created trigger from the list of available triggers. In order to
achieve this, one should write a positive integer into the
associated file, representing the id of the trigger that needs
to be removed. If the trigger can't be found, an invalid
argument message will be returned to the user.
......@@ -578,7 +578,7 @@
work together.
</para>
<sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title>
!Edrivers/iio/industrialio-triggered-buffer.c
!Edrivers/iio/buffer/industrialio-triggered-buffer.c
!Finclude/linux/iio/iio.h iio_buffer_setup_ops
......
......@@ -54,7 +54,6 @@ epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
fsl,mma8452 MMA8452Q: 3-axis 12-bit / 8-bit Digital Accelerometer
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
......@@ -80,6 +79,7 @@ oki,ml86v7667 OKI ML86V7667 video decoder
ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus
pericom,pt7c4338 Real-time Clock Module
plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch
pulsedlight,lidar-lite-v2 Pulsedlight LIDAR range-finding sensor
ramtron,24c64 i2c serial eeprom (24cxx)
ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
......@@ -88,6 +88,7 @@ ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
sgx,vz89x SGX Sensortech VZ89X Sensors
sii,s35390a 2-wire CMOS real-time clock
skyworks,sky81452 Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
st-micro,24c256 i2c serial eeprom (24cxx)
......
Freescale MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC triaxial accelerometer
Required properties:
- compatible: should contain one of
* "fsl,mma8452"
* "fsl,mma8453"
* "fsl,mma8652"
* "fsl,mma8653"
- reg: the I2C address of the chip
Optional properties:
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for GPIO IRQ
Example:
mma8453fc@1d {
compatible = "fsl,mma8453";
reg = <0x1d>;
interrupt-parent = <&gpio1>;
interrupts = <5 0>;
};
Holt Integrated Circuits HI-8435 threshold detector bindings
Required properties:
- compatible: should be "holt,hi8435"
- reg: spi chip select number for the device
Recommended properties:
- spi-max-frequency: definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- gpios: GPIO used for controlling the reset pin
Example:
sensor@0 {
compatible = "holt,hi8435";
reg = <0>;
gpios = <&gpio6 1 0>;
spi-max-frequency = <1000000>;
};
* Avago APDS9960 gesture/RGB/ALS/proximity sensor
http://www.avagotech.com/docs/AV02-4191EN
Required properties:
- compatible: must be "avago,apds9960"
- reg: the I2c address of the sensor
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts : the sole interrupt generated by the device
Refer to interrupt-controller/interrupts.txt for generic interrupt client
node bindings.
Example:
apds9960@39 {
compatible = "avago,apds9960";
reg = <0x39>;
interrupt-parent = <&gpio1>;
interrupts = <16 1>;
};
* UPISEMI us5182d I2C ALS and Proximity sensor
Required properties:
- compatible: must be "upisemi,usd5182"
- reg: the I2C address of the device
Optional properties:
- upisemi,glass-coef: glass attenuation factor - compensation factor of
resolution 1000 for material transmittance.
- upisemi,dark-ths: array of 8 elements containing 16-bit thresholds (adc
counts) corresponding to every scale.
- upisemi,upper-dark-gain: 8-bit dark gain compensation factor(4 int and 4
fractional bits - Q4.4) applied when light > threshold
- upisemi,lower-dark-gain: 8-bit dark gain compensation factor(4 int and 4
fractional bits - Q4.4) applied when light < threshold
If the optional properties are not specified these factors will default to the
values in the below example.
The glass-coef defaults to no compensation for the covering material.
The threshold array defaults to experimental values that work with US5182D
sensor on evaluation board - roughly between 12-32 lux.
There will be no dark-gain compensation by default when ALS > thresh
(0 * dark-gain), and a 1.35 compensation factor when ALS < thresh.
Example:
usd5182@39 {
compatible = "upisemi,usd5182";
reg = <0x39>;
upisemi,glass-coef = < 1000 >;
upisemi,dark-ths = /bits/ 16 <170 200 512 512 800 2000 4000 8000>;
upisemi,upper-dark-gain = /bits/ 8 <0x00>;
upisemi,lower-dark-gain = /bits/ 8 <0x16>;
};
......@@ -101,6 +101,7 @@ himax Himax Technologies, Inc.
hisilicon Hisilicon Limited.
hit Hitachi Ltd.
hitex Hitex Development Tools
holt Holt Integrated Circuits, Inc.
honeywell Honeywell
hp Hewlett Packard
i2se I2SE GmbH
......@@ -169,6 +170,7 @@ phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
plathome Plat'Home Co., Ltd.
pixcir PIXCIR MICROELECTRONICS Co., Ltd
pulsedlight PulsedLight, Inc
powervr PowerVR (deprecated, use img)
qca Qualcomm Atheros, Inc.
qcom Qualcomm Technologies, Inc
......@@ -191,6 +193,7 @@ sbs Smart Battery System
schindler Schindler
seagate Seagate Technology PLC
semtech Semtech Corporation
sgx SGX Sensortech
sharp Sharp Corporation
sil Silicon Image
silabs Silicon Laboratories
......@@ -223,6 +226,7 @@ toshiba Toshiba Corporation
toumaz Toumaz
tplink TP-LINK Technologies Co., Ltd.
truly Truly Semiconductors Limited
upisemi uPI Semiconductor Corp.
usi Universal Scientific Industrial Co., Ltd.
v3 V3 Semiconductor
variscite Variscite Ltd.
......
......@@ -6918,6 +6918,13 @@ S: Supported
F: include/linux/mlx5/
F: drivers/infiniband/hw/mlx5/
MELEXIS MLX90614 DRIVER
M: Crt Mori <cmo@melexis.com>
L: linux-iio@vger.kernel.org
W: http://www.melexis.com
S: Supported
F: drivers/iio/temperature/mlx90614.c
MN88472 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
......
......@@ -19,27 +19,7 @@ config IIO_BUFFER
acquisition methods.
if IIO_BUFFER
config IIO_BUFFER_CB
bool "IIO callback buffer used for push in-kernel interfaces"
help
Should be selected by any drivers that do in-kernel push
usage. That is, those where the data is pushed to the consumer.
config IIO_KFIFO_BUF
tristate "Industrial I/O buffering based on kfifo"
help
A simple fifo based on kfifo. Note that this currently provides
no buffer events so it is up to userspace to work out how
often to read from the buffer.
config IIO_TRIGGERED_BUFFER
tristate
select IIO_TRIGGER
select IIO_KFIFO_BUF
help
Provides helper functions for setting up triggered buffers.
source "drivers/iio/buffer/Kconfig"
endif # IIO_BUFFER
config IIO_TRIGGER
......@@ -58,9 +38,16 @@ config IIO_CONSUMERS_PER_TRIGGER
This value controls the maximum number of consumers that a
given trigger may handle. Default is 2.
config IIO_TRIGGERED_EVENT
tristate
select IIO_TRIGGER
help
Provides helper functions for setting up triggered events.
source "drivers/iio/accel/Kconfig"
source "drivers/iio/adc/Kconfig"
source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/chemical/Kconfig"
source "drivers/iio/common/Kconfig"
source "drivers/iio/dac/Kconfig"
source "drivers/iio/frequency/Kconfig"
......
......@@ -6,14 +6,14 @@ obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
obj-y += accel/
obj-y += adc/
obj-y += amplifiers/
obj-y += buffer/
obj-y += chemical/
obj-y += common/
obj-y += dac/
obj-y += gyro/
......
......@@ -100,13 +100,13 @@ config KXCJK1013
be called kxcjk-1013.
config MMA8452
tristate "Freescale MMA8452Q Accelerometer Driver"
tristate "Freescale MMA8452Q and similar Accelerometers Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the Freescale MMA8452Q 3-axis
accelerometer.
Say yes here to build support for the following Freescale 3-axis
accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
To compile this driver as a module, choose M here: the module
will be called mma8452.
......@@ -137,6 +137,19 @@ config MMA9553
To compile this driver as a module, choose M here: the module
will be called mma9553.
config MXC4005
tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select REGMAP_I2C
help
Say yes here to build support for the Memsic MXC4005XC 3-axis
accelerometer.
To compile this driver as a module, choose M. The module will be
called mxc4005.
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
......
......@@ -14,6 +14,8 @@ obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o
obj-$(CONFIG_MMA9551) += mma9551.o
obj-$(CONFIG_MMA9553) += mma9553.o
obj-$(CONFIG_MXC4005) += mxc4005.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
......
This diff is collapsed.
This diff is collapsed.
......@@ -618,6 +618,7 @@ static const struct iio_info accel_info = {
.attrs = &st_accel_attribute_group,
.read_raw = &st_accel_read_raw,
.write_raw = &st_accel_write_raw,
.debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
......
......@@ -149,6 +149,17 @@ config BERLIN2_ADC
Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
temperature measurement.
config CC10001_ADC
tristate "Cosmic Circuits 10001 ADC driver"
depends on HAS_IOMEM && HAVE_CLK && REGULATOR
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Cosmic Circuits 10001 ADC.
This driver can also be built as a module. If so, the module will be
called cc10001_adc.
config DA9150_GPADC
tristate "Dialog DA9150 GPADC driver support"
depends on MFD_DA9150
......@@ -161,17 +172,6 @@ config DA9150_GPADC
To compile this driver as a module, choose M here: the module will be
called berlin2-adc.
config CC10001_ADC
tristate "Cosmic Circuits 10001 ADC driver"
depends on HAS_IOMEM && HAVE_CLK && REGULATOR
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Cosmic Circuits 10001 ADC.
This driver can also be built as a module. If so, the module will be
called cc10001_adc.
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
......@@ -183,6 +183,17 @@ config EXYNOS_ADC
To compile this driver as a module, choose M here: the module will be
called exynos_adc.
config HI8435
tristate "Holt Integrated Circuits HI-8435 threshold detector"
select IIO_TRIGGERED_EVENT
depends on SPI
help
If you say yes here you get support for Holt Integrated Circuits
HI-8435 chip.
This driver can also be built as a module. If so, the module will be
called hi8435.
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
......@@ -361,6 +372,8 @@ config TWL6030_GPADC
config VF610_ADC
tristate "Freescale vf610 ADC driver"
depends on OF
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to support for Vybrid board analog-to-digital converter.
Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX.
......
......@@ -16,9 +16,10 @@ obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
......
......@@ -27,13 +27,13 @@
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */
#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
#define BERLIN2_SM_CTRL_ADC_SEL_MASK GENMASK(8, 5)
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK (0x3 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK GENMASK(11, 10)
#define BERLIN2_SM_CTRL_ADC_START BIT(12)
#define BERLIN2_SM_CTRL_ADC_RESET BIT(13)
#define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14)
......@@ -50,7 +50,7 @@
#define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */
#define BERLIN2_SM_CTRL_TSEN_RESET BIT(29)
#define BERLIN2_SM_ADC_DATA 0x20
#define BERLIN2_SM_ADC_MASK 0x3ff
#define BERLIN2_SM_ADC_MASK GENMASK(9, 0)
#define BERLIN2_SM_ADC_STATUS 0x1c
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0)
......@@ -65,9 +65,9 @@
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
#define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */
#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK (0x1 << 21)
#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK BIT(21)
#define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22)
#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK (0xf << 22)
#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK GENMASK(25, 22)
struct berlin2_adc_priv {
struct regmap *regmap;
......@@ -78,13 +78,13 @@ struct berlin2_adc_priv {
};
#define BERLIN2_ADC_CHANNEL(n, t) \
{ \
.channel = n, \
.datasheet_name = "channel"#n, \
.type = t, \
.indexed = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
{ \
.channel = n, \
.datasheet_name = "channel"#n, \
.type = t, \
.indexed = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static const struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
......@@ -111,18 +111,24 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
mutex_lock(&priv->lock);
/* Enable the interrupts */
regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(channel));
/* Configure the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_RESET | BERLIN2_SM_CTRL_ADC_SEL_MASK
| BERLIN2_SM_CTRL_ADC_START,
BERLIN2_SM_CTRL_ADC_SEL(channel) | BERLIN2_SM_CTRL_ADC_START);
BERLIN2_SM_CTRL_ADC_RESET |
BERLIN2_SM_CTRL_ADC_SEL_MASK |
BERLIN2_SM_CTRL_ADC_START,
BERLIN2_SM_CTRL_ADC_SEL(channel) |
BERLIN2_SM_CTRL_ADC_START);
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
msecs_to_jiffies(1000));
msecs_to_jiffies(1000));
/* Disable the interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
if (ret == 0)
ret = -ETIMEDOUT;
......@@ -132,7 +138,7 @@ static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
}
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_START, 0);
BERLIN2_SM_CTRL_ADC_START, 0);
data = priv->data;
priv->data_available = false;
......@@ -149,24 +155,31 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
mutex_lock(&priv->lock);
/* Enable interrupts */
regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN);
/* Configure the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE,
BERLIN2_SM_CTRL_ADC_ROTATE);
BERLIN2_SM_CTRL_TSEN_RESET |
BERLIN2_SM_CTRL_ADC_ROTATE,
BERLIN2_SM_CTRL_ADC_ROTATE);
/* Configure the temperature sensor */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
BERLIN2_SM_TSEN_CTRL_TRIM_MASK | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK
| BERLIN2_SM_TSEN_CTRL_START,
BERLIN2_SM_TSEN_CTRL_TRIM(3) | BERLIN2_SM_TSEN_CTRL_SETTLING_12
| BERLIN2_SM_TSEN_CTRL_START);
BERLIN2_SM_TSEN_CTRL_TRIM_MASK |
BERLIN2_SM_TSEN_CTRL_SETTLING_MASK |
BERLIN2_SM_TSEN_CTRL_START,
BERLIN2_SM_TSEN_CTRL_TRIM(3) |
BERLIN2_SM_TSEN_CTRL_SETTLING_12 |
BERLIN2_SM_TSEN_CTRL_START);
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
msecs_to_jiffies(1000));
msecs_to_jiffies(1000));
/* Disable interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
if (ret == 0)
ret = -ETIMEDOUT;
......@@ -176,7 +189,7 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
}
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
BERLIN2_SM_TSEN_CTRL_START, 0);
BERLIN2_SM_TSEN_CTRL_START, 0);
data = priv->data;
priv->data_available = false;
......@@ -187,10 +200,9 @@ static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
}
static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
int temp;
switch (mask) {
......@@ -198,10 +210,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_VOLTAGE)
return -EINVAL;
/* Enable the interrupts */
regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(chan->channel));
*val = berlin2_adc_read(indio_dev, chan->channel);
if (*val < 0)
return *val;
......@@ -211,10 +219,6 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_TEMP)
return -EINVAL;
/* Enable interrupts */
regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN);
temp = berlin2_adc_tsen_read(indio_dev);
if (temp < 0)
return temp;
......@@ -306,12 +310,12 @@ static int berlin2_adc_probe(struct platform_device *pdev)
return tsen_irq;
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
pdev->dev.driver->name, indio_dev);
pdev->dev.driver->name, indio_dev);
if (ret)
return ret;
ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
0, pdev->dev.driver->name, indio_dev);
0, pdev->dev.driver->name, indio_dev);
if (ret)
return ret;
......@@ -328,13 +332,14 @@ static int berlin2_adc_probe(struct platform_device *pdev)
/* Power up the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER);
BERLIN2_SM_CTRL_ADC_POWER,
BERLIN2_SM_CTRL_ADC_POWER);
ret = iio_device_register(indio_dev);
if (ret) {
/* Power down the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, 0);
BERLIN2_SM_CTRL_ADC_POWER, 0);
return ret;
}
......@@ -350,7 +355,7 @@ static int berlin2_adc_remove(struct platform_device *pdev)
/* Power down the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, 0);
BERLIN2_SM_CTRL_ADC_POWER, 0);
return 0;
}
......
This diff is collapsed.
......@@ -508,6 +508,7 @@ static int max1027_remove(struct spi_device *spi)
static struct spi_driver max1027_driver = {
.driver = {
.name = "max1027",
.of_match_table = of_match_ptr(max1027_adc_dt_ids),
.owner = THIS_MODULE,
},
.probe = max1027_probe,
......
......@@ -404,6 +404,7 @@ MODULE_DEVICE_TABLE(spi, mcp320x_id);
static struct spi_driver mcp320x_driver = {
.driver = {
.name = "mcp320x",
.of_match_table = of_match_ptr(mcp320x_dt_ids),
.owner = THIS_MODULE,
},
.probe = mcp320x_probe,
......
......@@ -174,6 +174,13 @@ static int adc128_remove(struct spi_device *spi)
return 0;
}
static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc128s052", },
{ .compatible = "ti,adc122s021", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0}, /* index into adc128_config */
{ "adc122s021", 1},
......@@ -184,6 +191,7 @@ MODULE_DEVICE_TABLE(spi, adc128_id);
static struct spi_driver adc128_driver = {
.driver = {
.name = "adc128s052",
.of_match_table = of_match_ptr(adc128_of_match),
.owner = THIS_MODULE,
},
.probe = adc128_probe,
......
......@@ -875,6 +875,7 @@ static const struct of_device_id of_twl6030_match_tbl[] = {
},
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl);
static int twl6030_gpadc_probe(struct platform_device *pdev)
{
......
......@@ -34,8 +34,11 @@
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/driver.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
/* This will be the driver name the kernel reports */
#define DRIVER_NAME "vf610-adc"
......@@ -170,6 +173,7 @@ struct vf610_adc {
u32 sample_freq_avail[5];
struct completion completion;
u16 buffer[8];
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
......@@ -505,12 +509,24 @@ static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.ext_info = vf610_ext_info, \
.scan_index = (_idx), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
}
#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.scan_index = (_idx), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
}, \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
......@@ -531,6 +547,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
IIO_CHAN_SOFT_TIMESTAMP(32),
/* sentinel */
};
......@@ -559,13 +576,20 @@ static int vf610_adc_read_data(struct vf610_adc *info)
static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
{
struct vf610_adc *info = (struct vf610_adc *)dev_id;
struct iio_dev *indio_dev = (struct iio_dev *)dev_id;
struct vf610_adc *info = iio_priv(indio_dev);
int coco;
coco = readl(info->regs + VF610_REG_ADC_HS);
if (coco & VF610_ADC_HS_COCO0) {
info->value = vf610_adc_read_data(info);
complete(&info->completion);
if (iio_buffer_enabled(indio_dev)) {
info->buffer[0] = info->value;
iio_push_to_buffers_with_timestamp(indio_dev,
info->buffer, iio_get_time_ns());
iio_trigger_notify_done(indio_dev->trig);
} else
complete(&info->completion);
}
return IRQ_HANDLED;
......@@ -613,8 +637,12 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
reinit_completion(&info->completion);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
reinit_completion(&info->completion);
hc_cfg = VF610_ADC_ADCHC(chan->channel);
hc_cfg |= VF610_ADC_AIEN;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
......@@ -694,6 +722,56 @@ static int vf610_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
static int vf610_adc_buffer_postenable(struct iio_dev *indio_dev)
{
struct vf610_adc *info = iio_priv(indio_dev);
unsigned int channel;
int ret;
int val;
ret = iio_triggered_buffer_postenable(indio_dev);
if (ret)
return ret;
val = readl(info->regs + VF610_REG_ADC_GC);
val |= VF610_ADC_ADCON;
writel(val, info->regs + VF610_REG_ADC_GC);
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
val = VF610_ADC_ADCHC(channel);
val |= VF610_ADC_AIEN;
writel(val, info->regs + VF610_REG_ADC_HC0);
return 0;
}
static int vf610_adc_buffer_predisable(struct iio_dev *indio_dev)
{
struct vf610_adc *info = iio_priv(indio_dev);
unsigned int hc_cfg = 0;
int val;
val = readl(info->regs + VF610_REG_ADC_GC);
val &= ~VF610_ADC_ADCON;
writel(val, info->regs + VF610_REG_ADC_GC);
hc_cfg |= VF610_ADC_CONV_DISABLE;
hc_cfg &= ~VF610_ADC_AIEN;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
return iio_triggered_buffer_predisable(indio_dev);
}
static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
.postenable = &vf610_adc_buffer_postenable,
.predisable = &vf610_adc_buffer_predisable,
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
static int vf610_adc_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
......@@ -753,7 +831,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
ret = devm_request_irq(info->dev, irq,
vf610_adc_isr, 0,
dev_name(&pdev->dev), info);
dev_name(&pdev->dev), indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq);
return ret;
......@@ -806,15 +884,23 @@ static int vf610_adc_probe(struct platform_device *pdev)
vf610_adc_cfg_init(info);
vf610_adc_hw_init(info);
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
NULL, &iio_triggered_buffer_setup_ops);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't initialise the buffer\n");
goto error_iio_device_register;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register the device.\n");
goto error_iio_device_register;
goto error_adc_buffer_init;
}
return 0;
error_adc_buffer_init:
iio_triggered_buffer_cleanup(indio_dev);
error_iio_device_register:
clk_disable_unprepare(info->clk);
error_adc_clk_enable:
......@@ -829,6 +915,7 @@ static int vf610_adc_remove(struct platform_device *pdev)
struct vf610_adc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(info->vref);
clk_disable_unprepare(info->clk);
......
......@@ -273,33 +273,13 @@ static void xadc_zynq_unmask_worker(struct work_struct *work)
schedule_delayed_work(&xadc->zynq_unmask_work,
msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
}
}
static irqreturn_t xadc_zynq_threaded_interrupt_handler(int irq, void *devid)
{
struct iio_dev *indio_dev = devid;
struct xadc *xadc = iio_priv(indio_dev);
unsigned int alarm;
spin_lock_irq(&xadc->lock);
alarm = xadc->zynq_alarm;
xadc->zynq_alarm = 0;
spin_unlock_irq(&xadc->lock);
xadc_handle_events(indio_dev, xadc_zynq_transform_alarm(alarm));
/* unmask the required interrupts in timer. */
schedule_delayed_work(&xadc->zynq_unmask_work,
msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
return IRQ_HANDLED;
}
static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
{
struct iio_dev *indio_dev = devid;
struct xadc *xadc = iio_priv(indio_dev);
irqreturn_t ret = IRQ_HANDLED;
uint32_t status;
xadc_read_reg(xadc, XADC_ZYNQ_REG_INTSTS, &status);
......@@ -321,18 +301,23 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
status &= XADC_ZYNQ_INT_ALARM_MASK;
if (status) {
xadc->zynq_alarm |= status;
xadc->zynq_masked_alarm |= status;
/*
* mask the current event interrupt,
* unmask it when the interrupt is no more active.
*/
xadc_zynq_update_intmsk(xadc, 0, 0);
ret = IRQ_WAKE_THREAD;
xadc_handle_events(indio_dev,
xadc_zynq_transform_alarm(status));
/* unmask the required interrupts in timer. */
schedule_delayed_work(&xadc->zynq_unmask_work,
msecs_to_jiffies(XADC_ZYNQ_UNMASK_TIMEOUT));
}
spin_unlock(&xadc->lock);
return ret;
return IRQ_HANDLED;
}
#define XADC_ZYNQ_TCK_RATE_MAX 50000000
......@@ -437,7 +422,6 @@ static const struct xadc_ops xadc_zynq_ops = {
.setup = xadc_zynq_setup,
.get_dclk_rate = xadc_zynq_get_dclk_rate,
.interrupt_handler = xadc_zynq_interrupt_handler,
.threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
.update_alarm = xadc_zynq_update_alarm,
};
......@@ -1225,9 +1209,8 @@ static int xadc_probe(struct platform_device *pdev)
if (ret)
goto err_free_samplerate_trigger;
ret = request_threaded_irq(irq, xadc->ops->interrupt_handler,
xadc->ops->threaded_interrupt_handler,
0, dev_name(&pdev->dev), indio_dev);
ret = request_irq(irq, xadc->ops->interrupt_handler, 0,
dev_name(&pdev->dev), indio_dev);
if (ret)
goto err_clk_disable_unprepare;
......
......@@ -60,7 +60,6 @@ struct xadc {
enum xadc_external_mux_mode external_mux_mode;
unsigned int zynq_alarm;
unsigned int zynq_masked_alarm;
unsigned int zynq_intmask;
struct delayed_work zynq_unmask_work;
......@@ -79,7 +78,6 @@ struct xadc_ops {
void (*update_alarm)(struct xadc *, unsigned int);
unsigned long (*get_dclk_rate)(struct xadc *);
irqreturn_t (*interrupt_handler)(int, void *);
irqreturn_t (*threaded_interrupt_handler)(int, void *);
unsigned int flags;
};
......
......@@ -195,6 +195,7 @@ static const struct spi_device_id ad8366_id[] = {
{"ad8366", 0},
{}
};
MODULE_DEVICE_TABLE(spi, ad8366_id);
static struct spi_driver ad8366_driver = {
.driver = {
......
#
# Industrial I/O generic buffer implementations
#
# When adding new entries keep the list in alphabetical order
config IIO_BUFFER_CB
tristate "IIO callback buffer used for push in-kernel interfaces"
help
Should be selected by any drivers that do in-kernel push
usage. That is, those where the data is pushed to the consumer.
config IIO_KFIFO_BUF
tristate "Industrial I/O buffering based on kfifo"
help
A simple fifo based on kfifo. Note that this currently provides
no buffer events so it is up to userspace to work out how
often to read from the buffer.
config IIO_TRIGGERED_BUFFER
tristate
select IIO_TRIGGER
select IIO_KFIFO_BUF
help
Provides helper functions for setting up triggered buffers.
#
# Makefile for the industrial I/O buffer implementations
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
/* The industrial I/O callback buffer
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/export.h>
......@@ -124,3 +132,7 @@ struct iio_channel
return cb_buffer->channels;
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Industrial I/O callback buffer");
MODULE_LICENSE("GPL");
#
# Chemical sensors
#
menu "Chemical Sensors"
config VZ89X
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
depends on I2C
help
Say Y here to build I2C interface support for the SGX
Sensortech MiCS VZ89X VOC (Volatile Organic Compounds)
sensors
endmenu
#
# Makefile for IIO chemical sensors
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_VZ89X) += vz89x.o
/*
* vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors
*
* Copyright (C) 2015 Matt Ranostay <mranostay@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>
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define VZ89X_REG_MEASUREMENT 0x09
#define VZ89X_REG_MEASUREMENT_SIZE 6
#define VZ89X_VOC_CO2_IDX 0
#define VZ89X_VOC_SHORT_IDX 1
#define VZ89X_VOC_TVOC_IDX 2
#define VZ89X_VOC_RESISTANCE_IDX 3
struct vz89x_data {
struct i2c_client *client;
struct mutex lock;
unsigned long last_update;
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
};
static const struct iio_chan_spec vz89x_channels[] = {
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_CO2,
.modified = 1,
.info_mask_separate =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
.address = VZ89X_VOC_CO2_IDX,
},
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_VOC,
.modified = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = VZ89X_VOC_SHORT_IDX,
.extend_name = "short",
},
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_VOC,
.modified = 1,
.info_mask_separate =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
.address = VZ89X_VOC_TVOC_IDX,
},
{
.type = IIO_RESISTANCE,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.address = VZ89X_VOC_RESISTANCE_IDX,
},
};
static IIO_CONST_ATTR(in_concentration_co2_scale, "0.00000698689");
static IIO_CONST_ATTR(in_concentration_voc_scale, "0.00000000436681223");
static struct attribute *vz89x_attributes[] = {
&iio_const_attr_in_concentration_co2_scale.dev_attr.attr,
&iio_const_attr_in_concentration_voc_scale.dev_attr.attr,
NULL,
};
static const struct attribute_group vz89x_attrs_group = {
.attrs = vz89x_attributes,
};
static int vz89x_get_measurement(struct vz89x_data *data)
{
int ret;
int i;
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 0;
ret = i2c_smbus_write_word_data(data->client,
VZ89X_REG_MEASUREMENT, 0);
if (ret < 0)
return ret;
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
ret = i2c_smbus_read_byte(data->client);
if (ret < 0)
return ret;
data->buffer[i] = ret;
}
data->last_update = jiffies;
return 0;
}
static int vz89x_get_resistance_reading(struct vz89x_data *data)
{
u8 *buf = &data->buffer[VZ89X_VOC_TVOC_IDX];
return buf[0] | (buf[1] << 8) | (buf[2] << 16);
}
static int vz89x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct vz89x_data *data = iio_priv(indio_dev);
int ret = -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
ret = vz89x_get_measurement(data);
mutex_unlock(&data->lock);
if (ret)
return ret;
switch (chan->address) {
case VZ89X_VOC_CO2_IDX:
case VZ89X_VOC_SHORT_IDX:
case VZ89X_VOC_TVOC_IDX:
*val = data->buffer[chan->address];
return IIO_VAL_INT;
case VZ89X_VOC_RESISTANCE_IDX:
*val = vz89x_get_resistance_reading(data);
return IIO_VAL_INT;
default:
return -EINVAL;
}
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_RESISTANCE:
*val = 10;
return IIO_VAL_INT;
default:
return -EINVAL;
}
break;
case IIO_CHAN_INFO_OFFSET:
switch (chan->address) {
case VZ89X_VOC_CO2_IDX:
*val = 44;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
case VZ89X_VOC_TVOC_IDX:
*val = -13;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
return ret;
}
static const struct iio_info vz89x_info = {
.attrs = &vz89x_attrs_group,
.read_raw = vz89x_read_raw,
.driver_module = THIS_MODULE,
};
static int vz89x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct vz89x_data *data;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->last_update = jiffies - HZ;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &vz89x_info,
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vz89x_channels;
indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id vz89x_id[] = {
{ "vz89x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, vz89x_id);
static const struct of_device_id vz89x_dt_ids[] = {
{ .compatible = "sgx,vz89x" },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static struct i2c_driver vz89x_driver = {
.driver = {
.name = "vz89x",
.of_match_table = of_match_ptr(vz89x_dt_ids),
},
.probe = vz89x_probe,
.id_table = vz89x_id,
};
module_i2c_driver(vz89x_driver);
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors");
MODULE_LICENSE("GPL v2");
......@@ -44,6 +44,28 @@ static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
return err;
}
int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
u8 readdata;
int err;
if (!readval)
return sdata->tf->write_byte(&sdata->tb, sdata->dev,
(u8)reg, (u8)writeval);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata);
if (err < 0)
return err;
*readval = (unsigned)readdata;
return 0;
}
EXPORT_SYMBOL(st_sensors_debugfs_reg_access);
static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings,
unsigned int odr, struct st_sensor_odr_avl *odr_out)
{
......
......@@ -281,6 +281,12 @@ static int ad7303_remove(struct spi_device *spi)
return 0;
}
static const struct of_device_id ad7303_spi_of_match[] = {
{ .compatible = "adi,ad7303", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, ad7303_spi_of_match);
static const struct spi_device_id ad7303_spi_ids[] = {
{ "ad7303", 0 },
{}
......@@ -290,6 +296,7 @@ MODULE_DEVICE_TABLE(spi, ad7303_spi_ids);
static struct spi_driver ad7303_driver = {
.driver = {
.name = "ad7303",
.of_match_table = of_match_ptr(ad7303_spi_of_match),
.owner = THIS_MODULE,
},
.probe = ad7303_probe,
......
......@@ -387,6 +387,7 @@ static const struct of_device_id max5821_of_match[] = {
{ .compatible = "maxim,max5821" },
{ }
};
MODULE_DEVICE_TABLE(of, max5821_of_match);
static struct i2c_driver max5821_driver = {
.driver = {
......
......@@ -616,15 +616,24 @@ static int adf4350_remove(struct spi_device *spi)
return 0;
}
static const struct of_device_id adf4350_of_match[] = {
{ .compatible = "adi,adf4350", },
{ .compatible = "adi,adf4351", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adf4350_of_match);
static const struct spi_device_id adf4350_id[] = {
{"adf4350", 4350},
{"adf4351", 4351},
{}
};
MODULE_DEVICE_TABLE(spi, adf4350_id);
static struct spi_driver adf4350_driver = {
.driver = {
.name = "adf4350",
.of_match_table = of_match_ptr(adf4350_of_match),
.owner = THIS_MODULE,
},
.probe = adf4350_probe,
......
......@@ -52,15 +52,26 @@ config ADXRS450
config BMG160
tristate "BOSCH BMG160 Gyro Sensor"
depends on I2C
depends on (I2C || SPI_MASTER)
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select BMG160_I2C if (I2C)
select BMG160_SPI if (SPI)
help
Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
driver. This driver also supports BMI055 gyroscope.
Say yes here to build support for BOSCH BMG160 Tri-axis Gyro Sensor
driver connected via I2C or SPI. This driver also supports BMI055
gyroscope.
This driver can also be built as a module. If so, the module
will be called bmg160.
will be called bmg160_i2c or bmg160_spi.
config BMG160_I2C
tristate
select REGMAP_I2C
config BMG160_SPI
tristate
select REGMAP_SPI
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB
......
......@@ -8,7 +8,9 @@ obj-$(CONFIG_ADIS16130) += adis16130.o
obj-$(CONFIG_ADIS16136) += adis16136.o
obj-$(CONFIG_ADIS16260) += adis16260.o
obj-$(CONFIG_ADXRS450) += adxrs450.o
obj-$(CONFIG_BMG160) += bmg160.o
obj-$(CONFIG_BMG160) += bmg160_core.o
obj-$(CONFIG_BMG160_I2C) += bmg160_i2c.o
obj-$(CONFIG_BMG160_SPI) += bmg160_spi.o
obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o
......
#ifndef BMG160_H_
#define BMG160_H_
extern const struct dev_pm_ops bmg160_pm_ops;
int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name);
void bmg160_core_remove(struct device *dev);
#endif /* BMG160_H_ */
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include "bmg160.h"
static const struct regmap_config bmg160_regmap_i2c_conf = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x3f
};
static int bmg160_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
const char *name = NULL;
regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
if (id)
name = id->name;
return bmg160_core_probe(&client->dev, regmap, client->irq, name);
}
static int bmg160_i2c_remove(struct i2c_client *client)
{
bmg160_core_remove(&client->dev);
return 0;
}
static const struct acpi_device_id bmg160_acpi_match[] = {
{"BMG0160", 0},
{"BMI055B", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match);
static const struct i2c_device_id bmg160_i2c_id[] = {
{"bmg160", 0},
{"bmi055_gyro", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, bmg160_i2c_id);
static struct i2c_driver bmg160_i2c_driver = {
.driver = {
.name = "bmg160_i2c",
.acpi_match_table = ACPI_PTR(bmg160_acpi_match),
.pm = &bmg160_pm_ops,
},
.probe = bmg160_i2c_probe,
.remove = bmg160_i2c_remove,
.id_table = bmg160_i2c_id,
};
module_i2c_driver(bmg160_i2c_driver);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("BMG160 I2C Gyro driver");
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include "bmg160.h"
static const struct regmap_config bmg160_regmap_spi_conf = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x3f,
};
static int bmg160_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
const struct spi_device_id *id = spi_get_device_id(spi);
regmap = devm_regmap_init_spi(spi, &bmg160_regmap_spi_conf);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return bmg160_core_probe(&spi->dev, regmap, spi->irq, id->name);
}
static int bmg160_spi_remove(struct spi_device *spi)
{
bmg160_core_remove(&spi->dev);
return 0;
}
static const struct spi_device_id bmg160_spi_id[] = {
{"bmg160", 0},
{"bmi055_gyro", 0},
{}
};
MODULE_DEVICE_TABLE(spi, bmg160_spi_id);
static struct spi_driver bmg160_spi_driver = {
.driver = {
.name = "bmg160_spi",
.pm = &bmg160_pm_ops,
},
.probe = bmg160_spi_probe,
.remove = bmg160_spi_remove,
.id_table = bmg160_spi_id,
};
module_spi_driver(bmg160_spi_driver);
MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("BMG160 SPI Gyro driver");
......@@ -383,6 +383,7 @@ static const struct iio_info gyro_info = {
.attrs = &st_gyro_attribute_group,
.read_raw = &st_gyro_read_raw,
.write_raw = &st_gyro_write_raw,
.debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
......
......@@ -12,6 +12,16 @@ config DHT11
Other sensors should work as well as long as they speak the
same protocol.
config HDC100X
tristate "TI HDC100x relative humidity and temperature sensor"
depends on I2C
help
Say yes here to build support for the TI HDC100x series of
relative humidity and temperature sensors.
To compile this driver as a module, choose M here: the module
will be called hdc100x.
config SI7005
tristate "SI7005 relative humidity and temperature sensor"
depends on I2C
......
......@@ -3,5 +3,6 @@
#
obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_HDC100X) += hdc100x.o
obj-$(CONFIG_SI7005) += si7005.o
obj-$(CONFIG_SI7020) += si7020.o
/*
* hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
*
* Copyright (C) 2015 Matt Ranostay <mranostay@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/delay.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define HDC100X_REG_TEMP 0x00
#define HDC100X_REG_HUMIDITY 0x01
#define HDC100X_REG_CONFIG 0x02
#define HDC100X_REG_CONFIG_HEATER_EN BIT(13)
struct hdc100x_data {
struct i2c_client *client;
struct mutex lock;
u16 config;
/* integration time of the sensor */
int adc_int_us[2];
};
/* integration time in us */
static const int hdc100x_int_time[][3] = {
{ 6350, 3650, 0 }, /* IIO_TEMP channel*/
{ 6500, 3850, 2500 }, /* IIO_HUMIDITYRELATIVE channel */
};
/* HDC100X_REG_CONFIG shift and mask values */
static const struct {
int shift;
int mask;
} hdc100x_resolution_shift[2] = {
{ /* IIO_TEMP channel */
.shift = 10,
.mask = 1
},
{ /* IIO_HUMIDITYRELATIVE channel */
.shift = 8,
.mask = 2,
},
};
static IIO_CONST_ATTR(temp_integration_time_available,
"0.00365 0.00635");
static IIO_CONST_ATTR(humidityrelative_integration_time_available,
"0.0025 0.00385 0.0065");
static IIO_CONST_ATTR(out_current_heater_raw_available,
"0 1");
static struct attribute *hdc100x_attributes[] = {
&iio_const_attr_temp_integration_time_available.dev_attr.attr,
&iio_const_attr_humidityrelative_integration_time_available.dev_attr.attr,
&iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
NULL
};
static struct attribute_group hdc100x_attribute_group = {
.attrs = hdc100x_attributes,
};
static const struct iio_chan_spec hdc100x_channels[] = {
{
.type = IIO_TEMP,
.address = HDC100X_REG_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME) |
BIT(IIO_CHAN_INFO_OFFSET),
},
{
.type = IIO_HUMIDITYRELATIVE,
.address = HDC100X_REG_HUMIDITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME)
},
{
.type = IIO_CURRENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.extend_name = "heater",
.output = 1,
},
};
static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val)
{
int tmp = (~mask & data->config) | val;
int ret;
ret = i2c_smbus_write_word_swapped(data->client,
HDC100X_REG_CONFIG, tmp);
if (!ret)
data->config = tmp;
return ret;
}
static int hdc100x_set_it_time(struct hdc100x_data *data, int chan, int val2)
{
int shift = hdc100x_resolution_shift[chan].shift;
int ret = -EINVAL;
int i;
for (i = 0; i < ARRAY_SIZE(hdc100x_int_time[chan]); i++) {
if (val2 && val2 == hdc100x_int_time[chan][i]) {
ret = hdc100x_update_config(data,
hdc100x_resolution_shift[chan].mask << shift,
i << shift);
if (!ret)
data->adc_int_us[chan] = val2;
break;
}
}
return ret;
}
static int hdc100x_get_measurement(struct hdc100x_data *data,
struct iio_chan_spec const *chan)
{
struct i2c_client *client = data->client;
int delay = data->adc_int_us[chan->address];
int ret;
int val;
/* start measurement */
ret = i2c_smbus_write_byte(client, chan->address);
if (ret < 0) {
dev_err(&client->dev, "cannot start measurement");
return ret;
}
/* wait for integration time to pass */
usleep_range(delay, delay + 1000);
/*
* i2c_smbus_read_word_data cannot() be used here due to the command
* value not being understood and causes NAKs preventing any reading
* from being accessed.
*/
ret = i2c_smbus_read_byte(client);
if (ret < 0) {
dev_err(&client->dev, "cannot read high byte measurement");
return ret;
}
val = ret << 6;
ret = i2c_smbus_read_byte(client);
if (ret < 0) {
dev_err(&client->dev, "cannot read low byte measurement");
return ret;
}
val |= ret >> 2;
return val;
}
static int hdc100x_get_heater_status(struct hdc100x_data *data)
{
return !!(data->config & HDC100X_REG_CONFIG_HEATER_EN);
}
static int hdc100x_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct hdc100x_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW: {
int ret;
mutex_lock(&data->lock);
if (chan->type == IIO_CURRENT) {
*val = hdc100x_get_heater_status(data);
ret = IIO_VAL_INT;
} else {
ret = hdc100x_get_measurement(data, chan);
if (ret >= 0) {
*val = ret;
ret = IIO_VAL_INT;
}
}
mutex_unlock(&data->lock);
return ret;
}
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
*val2 = data->adc_int_us[chan->address];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP) {
*val = 165;
*val2 = 65536 >> 2;
return IIO_VAL_FRACTIONAL;
} else {
*val = 0;
*val2 = 10000;
return IIO_VAL_INT_PLUS_MICRO;
}
break;
case IIO_CHAN_INFO_OFFSET:
*val = -40;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int hdc100x_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct hdc100x_data *data = iio_priv(indio_dev);
int ret = -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
if (val != 0)
return -EINVAL;
mutex_lock(&data->lock);
ret = hdc100x_set_it_time(data, chan->address, val2);
mutex_unlock(&data->lock);
return ret;
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_CURRENT || val2 != 0)
return -EINVAL;
mutex_lock(&data->lock);
ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN,
val ? HDC100X_REG_CONFIG_HEATER_EN : 0);
mutex_unlock(&data->lock);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_info hdc100x_info = {
.read_raw = hdc100x_read_raw,
.write_raw = hdc100x_write_raw,
.attrs = &hdc100x_attribute_group,
.driver_module = THIS_MODULE,
};
static int hdc100x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct hdc100x_data *data;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &hdc100x_info;
indio_dev->channels = hdc100x_channels;
indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels);
/* be sure we are in a known state */
hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]);
hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]);
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id hdc100x_id[] = {
{ "hdc100x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, hdc100x_id);
static struct i2c_driver hdc100x_driver = {
.driver = {
.name = "hdc100x",
},
.probe = hdc100x_probe,
.id_table = hdc100x_id,
};
module_i2c_driver(hdc100x_driver);
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
MODULE_LICENSE("GPL");
......@@ -57,8 +57,12 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
*val = ret >> 2;
/*
* Humidity values can slightly exceed the 0-100%RH
* range and should be corrected by software
*/
if (chan->type == IIO_HUMIDITYRELATIVE)
*val &= GENMASK(11, 0);
*val = clamp_val(*val, 786, 13893);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP)
......
......@@ -75,6 +75,8 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_ENERGY] = "energy",
[IIO_DISTANCE] = "distance",
[IIO_VELOCITY] = "velocity",
[IIO_CONCENTRATION] = "concentration",
[IIO_RESISTANCE] = "resistance",
};
static const char * const iio_modifier_names[] = {
......@@ -111,6 +113,8 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
[IIO_MOD_I] = "i",
[IIO_MOD_Q] = "q",
[IIO_MOD_CO2] = "co2",
[IIO_MOD_VOC] = "voc",
};
/* relies on pairs of these shared then separate */
......@@ -962,7 +966,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
static void iio_dev_release(struct device *device)
{
struct iio_dev *indio_dev = dev_to_iio_dev(device);
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED))
iio_device_unregister_trigger_consumer(indio_dev);
iio_device_unregister_eventset(indio_dev);
iio_device_unregister_sysfs(indio_dev);
......@@ -1153,6 +1157,8 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (cmd == IIO_GET_EVENT_FD_IOCTL) {
fd = iio_event_getfd(indio_dev);
if (fd < 0)
return fd;
if (copy_to_user(ip, &fd, sizeof(fd)))
return -EFAULT;
return 0;
......@@ -1241,7 +1247,7 @@ int iio_device_register(struct iio_dev *indio_dev)
"Failed to register event set\n");
goto error_free_sysfs;
}
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED))
iio_device_register_trigger_consumer(indio_dev);
if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
......
......@@ -366,10 +366,18 @@ static ssize_t iio_trigger_write_current(struct device *dev,
indio_dev->trig = trig;
if (oldtrig)
if (oldtrig) {
if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
iio_trigger_detach_poll_func(oldtrig,
indio_dev->pollfunc_event);
iio_trigger_put(oldtrig);
if (indio_dev->trig)
}
if (indio_dev->trig) {
iio_trigger_get(indio_dev->trig);
if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
iio_trigger_attach_poll_func(indio_dev->trig,
indio_dev->pollfunc_event);
}
return len;
}
......
/*
* Copyright (C) 2015 Cogent Embedded, Inc.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_event.h>
#include <linux/iio/trigger_consumer.h>
/**
* iio_triggered_event_setup() - Setup pollfunc_event for triggered event
* @indio_dev: IIO device structure
* @h: Function which will be used as pollfunc_event top half
* @thread: Function which will be used as pollfunc_event bottom half
*
* This function combines some common tasks which will normally be performed
* when setting up a triggered event. It will allocate the pollfunc_event and
* set mode to use it for triggered event.
*
* Before calling this function the indio_dev structure should already be
* completely initialized, but not yet registered. In practice this means that
* this function should be called right before iio_device_register().
*
* To free the resources allocated by this function call
* iio_triggered_event_cleanup().
*/
int iio_triggered_event_setup(struct iio_dev *indio_dev,
irqreturn_t (*h)(int irq, void *p),
irqreturn_t (*thread)(int irq, void *p))
{
indio_dev->pollfunc_event = iio_alloc_pollfunc(h,
thread,
IRQF_ONESHOT,
indio_dev,
"%s_consumer%d",
indio_dev->name,
indio_dev->id);
if (indio_dev->pollfunc_event == NULL)
return -ENOMEM;
/* Flag that events polling is possible */
indio_dev->modes |= INDIO_EVENT_TRIGGERED;
return 0;
}
EXPORT_SYMBOL(iio_triggered_event_setup);
/**
* iio_triggered_event_cleanup() - Free resources allocated by iio_triggered_event_setup()
* @indio_dev: IIO device structure
*/
void iio_triggered_event_cleanup(struct iio_dev *indio_dev)
{
indio_dev->modes &= ~INDIO_EVENT_TRIGGERED;
iio_dealloc_pollfunc(indio_dev->pollfunc_event);
}
EXPORT_SYMBOL(iio_triggered_event_cleanup);
MODULE_AUTHOR("Vladimir Barinov");
MODULE_DESCRIPTION("IIO helper functions for setting up triggered events");
MODULE_LICENSE("GPL");
......@@ -50,6 +50,19 @@ config APDS9300
To compile this driver as a module, choose M here: the
module will be called apds9300.
config APDS9960
tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor"
select REGMAP_I2C
select IIO_BUFFER
select IIO_KFIFO_BUF
depends on I2C
help
Say Y here to build I2C interface support for the Avago
APDS9960 gesture/RGB/ALS/proximity sensor.
To compile this driver as a module, choose M here: the
module will be called apds9960
config BH1750
tristate "ROHM BH1750 ambient light sensor"
depends on I2C
......@@ -287,6 +300,16 @@ config TSL4531
To compile this driver as a module, choose M here: the
module will be called tsl4531.
config US5182D
tristate "UPISEMI light and proximity sensor"
depends on I2C
help
If you say yes here you get support for the UPISEMI US5182D
ambient light and proximity sensor.
This driver can also be built as a module. If so, the module
will be called us5182d.
config VCNL4000
tristate "VCNL4000 combined ALS and proximity sensor"
depends on I2C
......
......@@ -7,6 +7,7 @@ obj-$(CONFIG_ACPI_ALS) += acpi-als.o
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_APDS9960) += apds9960.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM3232) += cm3232.o
......@@ -27,4 +28,5 @@ obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
This diff is collapsed.
......@@ -793,7 +793,6 @@ static struct i2c_driver opt3001_driver = {
.driver = {
.name = "opt3001",
.of_match_table = of_match_ptr(opt3001_of_match),
.owner = THIS_MODULE,
},
};
......
......@@ -35,8 +35,8 @@
#define STK3310_REG_ID 0x3E
#define STK3310_MAX_REG 0x80
#define STK3310_STATE_EN_PS 0x01
#define STK3310_STATE_EN_ALS 0x02
#define STK3310_STATE_EN_PS BIT(0)
#define STK3310_STATE_EN_ALS BIT(1)
#define STK3310_STATE_STANDBY 0x00
#define STK3310_CHIP_ID_VAL 0x13
......@@ -241,8 +241,11 @@ static int stk3310_write_event(struct iio_dev *indio_dev,
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
regmap_field_read(data->reg_ps_gain, &index);
if (val > stk3310_ps_max[index])
ret = regmap_field_read(data->reg_ps_gain, &index);
if (ret < 0)
return ret;
if (val < 0 || val > stk3310_ps_max[index])
return -EINVAL;
if (dir == IIO_EV_DIR_RISING)
......@@ -266,9 +269,12 @@ static int stk3310_read_event_config(struct iio_dev *indio_dev,
enum iio_event_direction dir)
{
unsigned int event_val;
int ret;
struct stk3310_data *data = iio_priv(indio_dev);
regmap_field_read(data->reg_int_ps, &event_val);
ret = regmap_field_read(data->reg_int_ps, &event_val);
if (ret < 0)
return ret;
return event_val;
}
......@@ -307,14 +313,16 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type == IIO_LIGHT)
reg = STK3310_REG_ALS_DATA_MSB;
else if (chan->type == IIO_PROXIMITY)
reg = STK3310_REG_PS_DATA_MSB;
else
return -EINVAL;
reg = STK3310_REG_PS_DATA_MSB;
mutex_lock(&data->lock);
ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
if (ret < 0) {
......@@ -327,17 +335,23 @@ static int stk3310_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
if (chan->type == IIO_LIGHT)
regmap_field_read(data->reg_als_it, &index);
ret = regmap_field_read(data->reg_als_it, &index);
else
regmap_field_read(data->reg_ps_it, &index);
ret = regmap_field_read(data->reg_ps_it, &index);
if (ret < 0)
return ret;
*val = stk3310_it_table[index][0];
*val2 = stk3310_it_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_LIGHT)
regmap_field_read(data->reg_als_gain, &index);
ret = regmap_field_read(data->reg_als_gain, &index);
else
regmap_field_read(data->reg_ps_gain, &index);
ret = regmap_field_read(data->reg_ps_gain, &index);
if (ret < 0)
return ret;
*val = stk3310_scale_table[index][0];
*val2 = stk3310_scale_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
......@@ -354,6 +368,9 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
int index;
struct stk3310_data *data = iio_priv(indio_dev);
if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
index = stk3310_get_index(stk3310_it_table,
......@@ -368,7 +385,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
ret = regmap_field_write(data->reg_ps_it, index);
if (ret < 0)
dev_err(&data->client->dev,
"sensor configuration failed\n");
"sensor configuration failed\n");
mutex_unlock(&data->lock);
return ret;
......@@ -385,7 +402,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
ret = regmap_field_write(data->reg_ps_gain, index);
if (ret < 0)
dev_err(&data->client->dev,
"sensor configuration failed\n");
"sensor configuration failed\n");
mutex_unlock(&data->lock);
return ret;
}
......@@ -419,8 +436,8 @@ static int stk3310_set_state(struct stk3310_data *data, u8 state)
dev_err(&client->dev, "failed to change sensor state\n");
} else if (state != STK3310_STATE_STANDBY) {
/* Don't reset the 'enabled' flags if we're going in standby */
data->ps_enabled = !!(state & 0x01);
data->als_enabled = !!(state & 0x02);
data->ps_enabled = !!(state & STK3310_STATE_EN_PS);
data->als_enabled = !!(state & STK3310_STATE_EN_ALS);
}
mutex_unlock(&data->lock);
......@@ -435,7 +452,10 @@ static int stk3310_init(struct iio_dev *indio_dev)
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
regmap_read(data->regmap, STK3310_REG_ID, &chipid);
ret = regmap_read(data->regmap, STK3310_REG_ID, &chipid);
if (ret < 0)
return ret;
if (chipid != STK3310_CHIP_ID_VAL &&
chipid != STK3311_CHIP_ID_VAL) {
dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
......@@ -604,8 +624,13 @@ static int stk3310_probe(struct i2c_client *client,
if (ret < 0)
return ret;
if (client->irq < 0)
if (client->irq < 0) {
client->irq = stk3310_gpio_probe(client);
if (client->irq < 0) {
ret = client->irq;
goto err_standby;
}
}
if (client->irq >= 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
......@@ -614,17 +639,23 @@ static int stk3310_probe(struct i2c_client *client,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
STK3310_EVENT, indio_dev);
if (ret < 0)
if (ret < 0) {
dev_err(&client->dev, "request irq %d failed\n",
client->irq);
client->irq);
goto err_standby;
}
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
stk3310_set_state(data, STK3310_STATE_STANDBY);
goto err_standby;
}
return 0;
err_standby:
stk3310_set_state(data, STK3310_STATE_STANDBY);
return ret;
}
......@@ -648,7 +679,7 @@ static int stk3310_suspend(struct device *dev)
static int stk3310_resume(struct device *dev)
{
int state = 0;
u8 state = 0;
struct stk3310_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
......
......@@ -158,9 +158,9 @@ static int tsl4531_check_id(struct i2c_client *client)
case TSL45313_ID:
case TSL45315_ID:
case TSL45317_ID:
return 1;
default:
return 0;
default:
return -ENODEV;
}
}
......@@ -180,9 +180,10 @@ static int tsl4531_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->lock);
if (!tsl4531_check_id(client)) {
ret = tsl4531_check_id(client);
if (ret) {
dev_err(&client->dev, "no TSL4531 sensor\n");
return -ENODEV;
return ret;
}
ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
......
This diff is collapsed.
......@@ -24,6 +24,24 @@ config AK09911
help
Deprecated: AK09911 is now supported by AK8975 driver.
config BMC150_MAGN
tristate "Bosch BMC150 Magnetometer Driver"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the BMC150 magnetometer.
Currently this only supports the device via an i2c interface.
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing magnetometer part, which has
its own address and register map.
To compile this driver as a module, choose M here: the module will be
called bmc150_magn.
config MAG3110
tristate "Freescale MAG3110 3-Axis Magnetometer"
depends on I2C
......@@ -87,19 +105,4 @@ config IIO_ST_MAGN_SPI_3AXIS
depends on IIO_ST_MAGN_3AXIS
depends on IIO_ST_SENSORS_SPI
config BMC150_MAGN
tristate "Bosch BMC150 Magnetometer Driver"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the BMC150 magnetometer.
Currently this only supports the device via an i2c interface.
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing magnetometer part, which has
its own address and register map.
endmenu
......@@ -4,6 +4,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
obj-$(CONFIG_MAG3110) += mag3110.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
obj-$(CONFIG_MMC35240) += mmc35240.o
......@@ -14,5 +15,3 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
......@@ -560,6 +560,7 @@ static const struct iio_info magn_info = {
.attrs = &st_magn_attribute_group,
.read_raw = &st_magn_read_raw,
.write_raw = &st_magn_write_raw,
.debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
......
......@@ -400,6 +400,7 @@ static const struct iio_info press_info = {
.attrs = &st_press_attribute_group,
.read_raw = &st_press_read_raw,
.write_raw = &st_press_write_raw,
.debugfs_reg_access = &st_sensors_debugfs_reg_access,
};
#ifdef CONFIG_IIO_TRIGGER
......
......@@ -20,6 +20,18 @@ endmenu
menu "Proximity sensors"
config LIDAR_LITE_V2
tristate "PulsedLight LIDAR sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
depends on I2C
help
Say Y to build a driver for PulsedLight LIDAR range finding
sensor.
To compile this driver as a module, choose M here: the
module will be called pulsedlight-lite-v2
config SX9500
tristate "SX9500 Semtech proximity sensor"
select IIO_BUFFER
......
......@@ -4,4 +4,5 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_SX9500) += sx9500.o
......@@ -434,6 +434,12 @@ static int as3935_remove(struct spi_device *spi)
return 0;
}
static const struct of_device_id as3935_of_match[] = {
{ .compatible = "ams,as3935", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, as3935_of_match);
static const struct spi_device_id as3935_id[] = {
{"as3935", 0},
{},
......@@ -443,6 +449,7 @@ MODULE_DEVICE_TABLE(spi, as3935_id);
static struct spi_driver as3935_driver = {
.driver = {
.name = "as3935",
.of_match_table = of_match_ptr(as3935_of_match),
.owner = THIS_MODULE,
.pm = AS3935_PM_OPS,
},
......
This diff is collapsed.
......@@ -3,6 +3,7 @@
*
* Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
* Copyright (c) 2015 Essensium NV
* Copyright (c) 2015 Melexis
*
* 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
......@@ -20,7 +21,6 @@
* always has a pull-up so we do not need an extra GPIO to drive it high. If
* the "wakeup" GPIO is not given, power management will be disabled.
*
* TODO: filter configuration
*/
#include <linux/err.h>
......@@ -32,6 +32,7 @@
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define MLX90614_OP_RAM 0x00
#define MLX90614_OP_EEPROM 0x20
......@@ -79,6 +80,20 @@ struct mlx90614_data {
unsigned long ready_timestamp; /* in jiffies */
};
/* Bandwidth values for IIR filtering */
static const int mlx90614_iir_values[] = {77, 31, 20, 15, 723, 153, 110, 86};
static IIO_CONST_ATTR(in_temp_object_filter_low_pass_3db_frequency_available,
"0.15 0.20 0.31 0.77 0.86 1.10 1.53 7.23");
static struct attribute *mlx90614_attributes[] = {
&iio_const_attr_in_temp_object_filter_low_pass_3db_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group mlx90614_attr_group = {
.attrs = mlx90614_attributes,
};
/*
* Erase an address and write word.
* The mutex must be locked before calling.
......@@ -117,6 +132,42 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command,
return ret;
}
/*
* Find the IIR value inside mlx90614_iir_values array and return its position
* which is equivalent to the bit value in sensor register
*/
static inline s32 mlx90614_iir_search(const struct i2c_client *client,
int value)
{
int i;
s32 ret;
for (i = 0; i < ARRAY_SIZE(mlx90614_iir_values); ++i) {
if (value == mlx90614_iir_values[i])
break;
}
if (i == ARRAY_SIZE(mlx90614_iir_values))
return -EINVAL;
/*
* CONFIG register values must not be changed so
* we must read them before we actually write
* changes
*/
ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
if (ret > 0)
return ret;
/* Write changed values */
ret = mlx90614_write_word(client, MLX90614_CONFIG,
(i << MLX90614_CONFIG_IIR_SHIFT) |
(((u16) ((0x7 << MLX90614_CONFIG_FIR_SHIFT) |
((u16) ret & (~((u16) MLX90614_CONFIG_FIR_MASK))))) &
(~(u16) MLX90614_CONFIG_IIR_MASK)));
return ret;
}
#ifdef CONFIG_PM
/*
* If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since
......@@ -236,6 +287,21 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
*val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
}
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR setting with
FIR = 1024 */
mlx90614_power_get(data, false);
mutex_lock(&data->lock);
ret = i2c_smbus_read_word_data(data->client, MLX90614_CONFIG);
mutex_unlock(&data->lock);
mlx90614_power_put(data);
if (ret < 0)
return ret;
*val = mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] / 100;
*val2 = (mlx90614_iir_values[ret & MLX90614_CONFIG_IIR_MASK] % 100) *
10000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
......@@ -262,6 +328,18 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
mutex_unlock(&data->lock);
mlx90614_power_put(data);
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: /* IIR Filter setting */
if (val < 0 || val2 < 0)
return -EINVAL;
mlx90614_power_get(data, false);
mutex_lock(&data->lock);
ret = mlx90614_iir_search(data->client,
val * 100 + val2 / 10000);
mutex_unlock(&data->lock);
mlx90614_power_put(data);
return ret;
default:
return -EINVAL;
......@@ -275,6 +353,8 @@ static int mlx90614_write_raw_get_fmt(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_CALIBEMISSIVITY:
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
......@@ -294,7 +374,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.modified = 1,
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
......@@ -305,7 +386,8 @@ static const struct iio_chan_spec mlx90614_channels[] = {
.channel = 1,
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
BIT(IIO_CHAN_INFO_CALIBEMISSIVITY) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE),
},
......@@ -315,6 +397,7 @@ static const struct iio_info mlx90614_info = {
.read_raw = mlx90614_read_raw,
.write_raw = mlx90614_write_raw,
.write_raw_get_fmt = mlx90614_write_raw_get_fmt,
.attrs = &mlx90614_attr_group,
.driver_module = THIS_MODULE,
};
......@@ -569,5 +652,6 @@ module_i2c_driver(mlx90614_driver);
MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
MODULE_AUTHOR("Vianney le Clément de Saint-Marcq <vianney.leclement@essensium.com>");
MODULE_AUTHOR("Crt Mori <cmo@melexis.com>");
MODULE_DESCRIPTION("Melexis MLX90614 contactless IR temperature sensor driver");
MODULE_LICENSE("GPL");
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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