You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'iio-for-4.5b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Second set of IIO new drivers, functionality and cleanups for the 4.5 cycle.
The big one here is the configfs support which has been a long time in the
works but should allow for cleaner ways to do instantiation of those elements
of IIO that aren't directly connected to specific hardware. Lots of cool new
stuff we can use this for in the works!
New core stuff (basically all configfs support related)
* Configfs support
- Core support (was waiting for a configfs patch that went in around 4.4rc2)
- A little fixlet to add a configfs.h to contain a reference to the
configfs_subsystem structure.
* Some infrastructure to simplify handling of software based triggers
(i.e. ones with no actual hardware associated with them)
* A high resolution timer based trigger. This has been around for years
but until the configfs support was ready we didn't have a sensible way
of instantiating instances of it (the method used for the sysfs_trigger
has never been really satisfactory)
New Device Support
* AMS iAQ Volatile Organic Compounds sensor support.
* Freescale imx7d ADC driver
* Maxim MAX30100 oximeter driver (note that for these devices most of the
smart stuff will be in userspace - effectively they are just light sensors
with some interesting led synchronization as far as the kernel is concerned).
* Microchip mcp3421 support added to the mcp3422 driver.
* TI adc124s021 support added to the adc128s052 driver.
* TI ina219, inda226 power monitors. Note that there is an existing hwmon driver
for these parts, the usecase is somewhat different so it is unclear at this
point if the hwmon driver will eventually be replaced by a bridge from
this driver. In the meantime the Kconfig dependencies should prevent both
from being built.
New driver functionality
* us8152d power management support.
Cleanups, fixups
* Use list_for_each_entry_safe instead of list_for_each_safe with the entry
bit coded longhand.
* Select IRQ_WORK for IIO_DUMMY_EVGEN. This is a fix that somehow got lost
when the driver was moved so lets do it again.
* st-accel - drop an unused define.
* vz89x, lidar - optimize i2c transactions by using a single i2c tranfers
instead of multiple calls where supported (fall back to smbus calls as
before if not).
* Use dev_get_platdata() in staging drivers: tsl2x7x, adcs and frequency
drivers instead of direct access to the structure element.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
What: /config/iio
|
||||
Date: October 2015
|
||||
KernelVersion: 4.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
This represents Industrial IO configuration entry point
|
||||
directory. It contains sub-groups corresponding to IIO
|
||||
objects.
|
||||
|
||||
What: /config/iio/triggers
|
||||
Date: October 2015
|
||||
KernelVersion: 4.4
|
||||
Description:
|
||||
Industrial IO software triggers directory.
|
||||
|
||||
What: /config/iio/triggers/hrtimers
|
||||
Date: October 2015
|
||||
KernelVersion: 4.4
|
||||
Description:
|
||||
High resolution timers directory. Creating a directory here
|
||||
will result in creating a hrtimer trigger in the IIO subsystem.
|
||||
@@ -20,6 +20,7 @@ adi,adt7476 +/-1C TDM Extended Temp Range I.C
|
||||
adi,adt7490 +/-1C TDM Extended Temp Range I.C
|
||||
adi,adxl345 Three-Axis Digital Accelerometer
|
||||
adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
|
||||
ams,iaq-core AMS iAQ-Core VOC Sensor
|
||||
at,24c08 i2c serial eeprom (24cxx)
|
||||
atmel,24c00 i2c serial eeprom (24cxx)
|
||||
atmel,24c01 i2c serial eeprom (24cxx)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
Freescale imx7d ADC bindings
|
||||
|
||||
The devicetree bindings are for the ADC driver written for
|
||||
imx7d SoC.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx7d-adc"
|
||||
- reg: Offset and length of the register set for the ADC device
|
||||
- interrupts: The interrupt number for the ADC device
|
||||
- clocks: The root clock of the ADC controller
|
||||
- clock-names: Must contain "adc", matching entry in the clocks property
|
||||
- vref-supply: The regulator supply ADC reference voltage
|
||||
|
||||
Example:
|
||||
adc1: adc@30610000 {
|
||||
compatible = "fsl,imx7d-adc";
|
||||
reg = <0x30610000 0x10000>;
|
||||
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX7D_ADC_ROOT_CLK>;
|
||||
clock-names = "adc";
|
||||
vref-supply = <®_vcc_3v3_mcu>;
|
||||
};
|
||||
@@ -1,7 +1,8 @@
|
||||
* Microchip mcp3422/3/4/6/7/8 chip family (ADC)
|
||||
* Microchip mcp3421/2/3/4/6/7/8 chip family (ADC)
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be
|
||||
"microchip,mcp3421" or
|
||||
"microchip,mcp3422" or
|
||||
"microchip,mcp3423" or
|
||||
"microchip,mcp3424" or
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
* Texas Instruments' ADC128S052 and ADC122S021 ADC chip
|
||||
* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,adc128s052" or "ti,adc122s021"
|
||||
- compatible: Should be "ti,adc128s052", "ti,adc122s021" or "ti,adc124s021"
|
||||
- reg: spi chip select number for the device
|
||||
- vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
Maxim MAX30100 heart rate and pulse oximeter sensor
|
||||
|
||||
* https://datasheets.maximintegrated.com/en/ds/MAX30100.pdf
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "maxim,max30100"
|
||||
- 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:
|
||||
|
||||
max30100@057 {
|
||||
compatible = "maxim,max30100";
|
||||
reg = <57>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <16 2>;
|
||||
};
|
||||
@@ -7,13 +7,24 @@ Required properties:
|
||||
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
|
||||
|
||||
- upisemi,continuous: This chip has two power modes: one-shot (chip takes one
|
||||
measurement and then shuts itself down) and continuous (
|
||||
chip takes continuous measurements). The one-shot mode is
|
||||
more power-friendly but the continuous mode may be more
|
||||
reliable. If this property is specified the continuous
|
||||
mode will be used instead of the default one-shot one for
|
||||
raw reads.
|
||||
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
Industrial IIO configfs support
|
||||
|
||||
1. Overview
|
||||
|
||||
Configfs is a filesystem-based manager of kernel objects. IIO uses some
|
||||
objects that could be easily configured using configfs (e.g.: devices,
|
||||
triggers).
|
||||
|
||||
See Documentation/filesystems/configfs/configfs.txt for more information
|
||||
about how configfs works.
|
||||
|
||||
2. Usage
|
||||
|
||||
In order to use configfs support in IIO we need to select it at compile
|
||||
time via CONFIG_IIO_CONFIGFS config option.
|
||||
|
||||
Then, mount the configfs filesystem (usually under /config directory):
|
||||
|
||||
$ mkdir /config
|
||||
$ mount -t configfs none /config
|
||||
|
||||
At this point, all default IIO groups will be created and can be accessed
|
||||
under /config/iio. Next chapters will describe available IIO configuration
|
||||
objects.
|
||||
|
||||
3. Software triggers
|
||||
|
||||
One of the IIO default configfs groups is the "triggers" group. It is
|
||||
automagically accessible when the configfs is mounted and can be found
|
||||
under /config/iio/triggers.
|
||||
|
||||
IIO software triggers implementation offers support for creating multiple
|
||||
trigger types. A new trigger type is usually implemented as a separate
|
||||
kernel module following the interface in include/linux/iio/sw_trigger.h:
|
||||
|
||||
/*
|
||||
* drivers/iio/trigger/iio-trig-sample.c
|
||||
* sample kernel module implementing a new trigger type
|
||||
*/
|
||||
#include <linux/iio/sw_trigger.h>
|
||||
|
||||
|
||||
static struct iio_sw_trigger *iio_trig_sample_probe(const char *name)
|
||||
{
|
||||
/*
|
||||
* This allocates and registers an IIO trigger plus other
|
||||
* trigger type specific initialization.
|
||||
*/
|
||||
}
|
||||
|
||||
static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
|
||||
{
|
||||
/*
|
||||
* This undoes the actions in iio_trig_sample_probe
|
||||
*/
|
||||
}
|
||||
|
||||
static const struct iio_sw_trigger_ops iio_trig_sample_ops = {
|
||||
.probe = iio_trig_sample_probe,
|
||||
.remove = iio_trig_sample_remove,
|
||||
};
|
||||
|
||||
static struct iio_sw_trigger_type iio_trig_sample = {
|
||||
.name = "trig-sample",
|
||||
.owner = THIS_MODULE,
|
||||
.ops = &iio_trig_sample_ops,
|
||||
};
|
||||
|
||||
module_iio_sw_trigger_driver(iio_trig_sample);
|
||||
|
||||
Each trigger type has its own directory under /config/iio/triggers. Loading
|
||||
iio-trig-sample module will create 'trig-sample' trigger type directory
|
||||
/config/iio/triggers/trig-sample.
|
||||
|
||||
We support the following interrupt sources (trigger types):
|
||||
* hrtimer, uses high resolution timers as interrupt source
|
||||
|
||||
3.1 Hrtimer triggers creation and destruction
|
||||
|
||||
Loading iio-trig-hrtimer module will register hrtimer trigger types allowing
|
||||
users to create hrtimer triggers under /config/iio/triggers/hrtimer.
|
||||
|
||||
e.g:
|
||||
|
||||
$ mkdir /config/triggers/hrtimer/instance1
|
||||
$ rmdir /config/triggers/hrtimer/instance1
|
||||
|
||||
Each trigger can have one or more attributes specific to the trigger type.
|
||||
|
||||
3.2 "hrtimer" trigger types attributes
|
||||
|
||||
"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
|
||||
It does introduce the sampling_frequency attribute to trigger directory.
|
||||
@@ -22,6 +22,14 @@ if IIO_BUFFER
|
||||
source "drivers/iio/buffer/Kconfig"
|
||||
endif # IIO_BUFFER
|
||||
|
||||
config IIO_CONFIGFS
|
||||
tristate "Enable IIO configuration via configfs"
|
||||
select CONFIGFS_FS
|
||||
help
|
||||
This allows configuring various IIO bits through configfs
|
||||
(e.g. software triggers). For more info see
|
||||
Documentation/iio/iio_configfs.txt.
|
||||
|
||||
config IIO_TRIGGER
|
||||
bool "Enable triggered sampling support"
|
||||
help
|
||||
@@ -38,6 +46,14 @@ config IIO_CONSUMERS_PER_TRIGGER
|
||||
This value controls the maximum number of consumers that a
|
||||
given trigger may handle. Default is 2.
|
||||
|
||||
config IIO_SW_TRIGGER
|
||||
tristate "Enable software triggers support"
|
||||
select IIO_CONFIGFS
|
||||
help
|
||||
Provides IIO core support for software triggers. A software
|
||||
trigger can be created via configfs or directly by a driver
|
||||
using the API provided.
|
||||
|
||||
config IIO_TRIGGERED_EVENT
|
||||
tristate
|
||||
select IIO_TRIGGER
|
||||
@@ -53,6 +69,7 @@ source "drivers/iio/dac/Kconfig"
|
||||
source "drivers/iio/dummy/Kconfig"
|
||||
source "drivers/iio/frequency/Kconfig"
|
||||
source "drivers/iio/gyro/Kconfig"
|
||||
source "drivers/iio/health/Kconfig"
|
||||
source "drivers/iio/humidity/Kconfig"
|
||||
source "drivers/iio/imu/Kconfig"
|
||||
source "drivers/iio/light/Kconfig"
|
||||
|
||||
@@ -7,6 +7,8 @@ industrialio-y := industrialio-core.o industrialio-event.o inkern.o
|
||||
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
|
||||
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
|
||||
|
||||
obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
|
||||
obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
|
||||
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
|
||||
|
||||
obj-y += accel/
|
||||
@@ -19,6 +21,7 @@ obj-y += dac/
|
||||
obj-y += dummy/
|
||||
obj-y += gyro/
|
||||
obj-y += frequency/
|
||||
obj-y += health/
|
||||
obj-y += humidity/
|
||||
obj-y += imu/
|
||||
obj-y += light/
|
||||
|
||||
+22
-3
@@ -194,6 +194,25 @@ config HI8435
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called hi8435.
|
||||
|
||||
config INA2XX_ADC
|
||||
tristate "Texas Instruments INA2xx Power Monitors IIO driver"
|
||||
depends on I2C && !SENSORS_INA2XX
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_KFIFO_BUF
|
||||
help
|
||||
Say yes here to build support for TI INA2xx family of Power Monitors.
|
||||
This driver is mutually exclusive with the HWMON version.
|
||||
|
||||
config IMX7D_ADC
|
||||
tristate "IMX7D ADC driver"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for IMX7D ADC.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called imx7d_adc.
|
||||
|
||||
config LP8788_ADC
|
||||
tristate "LP8788 ADC driver"
|
||||
depends on MFD_LP8788
|
||||
@@ -332,11 +351,11 @@ config TI_ADC081C
|
||||
called ti-adc081c.
|
||||
|
||||
config TI_ADC128S052
|
||||
tristate "Texas Instruments ADC128S052/ADC122S021"
|
||||
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
|
||||
depends on SPI
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments ADC128S052
|
||||
and ADC122S021 chips.
|
||||
If you say yes here you get support for Texas Instruments ADC128S052,
|
||||
ADC122S021 and ADC124S021 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called ti-adc128s052.
|
||||
|
||||
@@ -20,6 +20,8 @@ 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_IMX7D_ADC) += imx7d_adc.o
|
||||
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
obj-$(CONFIG_MAX1363) += max1363.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -305,6 +305,10 @@ static const struct attribute_group mcp3422_attribute_group = {
|
||||
.attrs = mcp3422_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mcp3421_channels[] = {
|
||||
MCP3422_CHAN(0),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec mcp3422_channels[] = {
|
||||
MCP3422_CHAN(0),
|
||||
MCP3422_CHAN(1),
|
||||
@@ -352,6 +356,10 @@ static int mcp3422_probe(struct i2c_client *client,
|
||||
indio_dev->info = &mcp3422_info;
|
||||
|
||||
switch (adc->id) {
|
||||
case 1:
|
||||
indio_dev->channels = mcp3421_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
@@ -383,6 +391,7 @@ static int mcp3422_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mcp3422_id[] = {
|
||||
{ "mcp3421", 1 },
|
||||
{ "mcp3422", 2 },
|
||||
{ "mcp3423", 3 },
|
||||
{ "mcp3424", 4 },
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
|
||||
*
|
||||
* Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip.
|
||||
* Driver for Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip.
|
||||
* Datasheets can be found here:
|
||||
* 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
|
||||
@@ -114,9 +115,17 @@ static const struct iio_chan_spec adc122s021_channels[] = {
|
||||
ADC128_VOLTAGE_CHANNEL(1),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adc124s021_channels[] = {
|
||||
ADC128_VOLTAGE_CHANNEL(0),
|
||||
ADC128_VOLTAGE_CHANNEL(1),
|
||||
ADC128_VOLTAGE_CHANNEL(2),
|
||||
ADC128_VOLTAGE_CHANNEL(3),
|
||||
};
|
||||
|
||||
static const struct adc128_configuration adc128_config[] = {
|
||||
{ adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
|
||||
{ adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
|
||||
{ adc124s021_channels, ARRAY_SIZE(adc124s021_channels) },
|
||||
};
|
||||
|
||||
static const struct iio_info adc128_info = {
|
||||
@@ -177,6 +186,7 @@ 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,adc124s021", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc128_of_match);
|
||||
@@ -184,6 +194,7 @@ 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},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adc128_id);
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
menu "Chemical Sensors"
|
||||
|
||||
config IAQCORE
|
||||
tristate "AMS iAQ-Core VOC sensors"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here to build I2C interface support for the AMS
|
||||
iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
|
||||
sensors
|
||||
|
||||
config VZ89X
|
||||
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
|
||||
depends on I2C
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
|
||||
obj-$(CONFIG_VZ89X) += vz89x.o
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* ams-iaq-core.c - Support for AMS iAQ-Core 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>
|
||||
|
||||
#define AMS_IAQCORE_DATA_SIZE 9
|
||||
|
||||
#define AMS_IAQCORE_VOC_CO2_IDX 0
|
||||
#define AMS_IAQCORE_VOC_RESISTANCE_IDX 1
|
||||
#define AMS_IAQCORE_VOC_TVOC_IDX 2
|
||||
|
||||
struct ams_iaqcore_reading {
|
||||
__be16 co2_ppm;
|
||||
u8 status;
|
||||
__be32 resistance;
|
||||
__be16 voc_ppb;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct ams_iaqcore_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
unsigned long last_update;
|
||||
|
||||
struct ams_iaqcore_reading buffer;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ams_iaqcore_channels[] = {
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_CO2,
|
||||
.modified = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.address = AMS_IAQCORE_VOC_CO2_IDX,
|
||||
},
|
||||
{
|
||||
.type = IIO_RESISTANCE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.address = AMS_IAQCORE_VOC_RESISTANCE_IDX,
|
||||
},
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_VOC,
|
||||
.modified = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
.address = AMS_IAQCORE_VOC_TVOC_IDX,
|
||||
},
|
||||
};
|
||||
|
||||
static int ams_iaqcore_read_measurement(struct ams_iaqcore_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
struct i2c_msg msg = {
|
||||
.addr = client->addr,
|
||||
.flags = client->flags | I2C_M_RD,
|
||||
.len = AMS_IAQCORE_DATA_SIZE,
|
||||
.buf = (char *) &data->buffer,
|
||||
};
|
||||
|
||||
ret = i2c_transfer(client->adapter, &msg, 1);
|
||||
|
||||
return (ret == AMS_IAQCORE_DATA_SIZE) ? 0 : ret;
|
||||
}
|
||||
|
||||
static int ams_iaqcore_get_measurement(struct ams_iaqcore_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* sensor can only be polled once a second max per datasheet */
|
||||
if (!time_after(jiffies, data->last_update + HZ))
|
||||
return 0;
|
||||
|
||||
ret = ams_iaqcore_read_measurement(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->last_update = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ams_iaqcore_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct ams_iaqcore_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_PROCESSED)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = ams_iaqcore_get_measurement(data);
|
||||
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
switch (chan->address) {
|
||||
case AMS_IAQCORE_VOC_CO2_IDX:
|
||||
*val = 0;
|
||||
*val2 = be16_to_cpu(data->buffer.co2_ppm);
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
case AMS_IAQCORE_VOC_RESISTANCE_IDX:
|
||||
*val = be32_to_cpu(data->buffer.resistance);
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case AMS_IAQCORE_VOC_TVOC_IDX:
|
||||
*val = 0;
|
||||
*val2 = be16_to_cpu(data->buffer.voc_ppb);
|
||||
ret = IIO_VAL_INT_PLUS_NANO;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
err_out:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_info ams_iaqcore_info = {
|
||||
.read_raw = ams_iaqcore_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ams_iaqcore_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct ams_iaqcore_data *data;
|
||||
|
||||
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;
|
||||
|
||||
/* so initial reading will complete */
|
||||
data->last_update = jiffies - HZ;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &ams_iaqcore_info,
|
||||
indio_dev->name = dev_name(&client->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
indio_dev->channels = ams_iaqcore_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ams_iaqcore_channels);
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ams_iaqcore_id[] = {
|
||||
{ "ams-iaq-core", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id);
|
||||
|
||||
static const struct of_device_id ams_iaqcore_dt_ids[] = {
|
||||
{ .compatible = "ams,iaq-core" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ams_iaqcore_dt_ids);
|
||||
|
||||
static struct i2c_driver ams_iaqcore_driver = {
|
||||
.driver = {
|
||||
.name = "ams-iaq-core",
|
||||
.of_match_table = of_match_ptr(ams_iaqcore_dt_ids),
|
||||
},
|
||||
.probe = ams_iaqcore_probe,
|
||||
.id_table = ams_iaqcore_id,
|
||||
};
|
||||
module_i2c_driver(ams_iaqcore_driver);
|
||||
|
||||
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
|
||||
MODULE_DESCRIPTION("AMS iAQ-Core VOC sensors");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -34,8 +34,9 @@
|
||||
struct vz89x_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
unsigned long last_update;
|
||||
int (*xfer)(struct vz89x_data *data, u8 cmd);
|
||||
|
||||
unsigned long last_update;
|
||||
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
|
||||
};
|
||||
|
||||
@@ -100,27 +101,60 @@ static int vz89x_measurement_is_valid(struct vz89x_data *data)
|
||||
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
|
||||
}
|
||||
|
||||
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
struct i2c_msg msg[2];
|
||||
int ret;
|
||||
u8 buf[3] = { cmd, 0, 0};
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = client->flags;
|
||||
msg[0].len = 3;
|
||||
msg[0].buf = (char *) &buf;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = client->flags | I2C_M_RD;
|
||||
msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
|
||||
msg[1].buf = (char *) &data->buffer;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
|
||||
return (ret == 2) ? 0 : ret;
|
||||
}
|
||||
|
||||
static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = i2c_smbus_write_word_data(client, cmd, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
|
||||
ret = i2c_smbus_read_byte(client);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->buffer[i] = ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
|
||||
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;
|
||||
}
|
||||
|
||||
ret = vz89x_measurement_is_valid(data);
|
||||
if (ret)
|
||||
return -EAGAIN;
|
||||
@@ -204,15 +238,19 @@ static int vz89x_probe(struct i2c_client *client,
|
||||
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);
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
data->xfer = vz89x_i2c_xfer;
|
||||
else if (i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
|
||||
data->xfer = vz89x_smbus_xfer;
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->last_update = jiffies - HZ;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user