Commit 39272dde authored by Linus Torvalds's avatar Linus Torvalds

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

Pull staging driver updates from Greg KH:
 "Here is the big staging driver pull request for 4.5-rc1.

  Lots of cleanups and fixes here, not as many as some releases, but
  800+ isn't that bad.  Full details in the shortlog.  All of these have
  been in linux-next for a while"

* tag 'staging-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (843 commits)
  Revert "arm64: dts: Add dts files to enable ION on Hi6220 SoC."
  staging: gdm724x: constify tty_port_operations structs
  staging: gdm72xx: add userspace data struct
  staging: gdm72xx: Replace timeval with ktime_t
  iio: adc: ina2xx: Fix incorrect report of data endianness to userspace.
  iio: light: us5182d: Refactor read_raw function
  iio: light: us5182d: Add interrupt support and events
  iio: light: us5182d: Fix enable status inconcistency
  iio: Make IIO value formating function globally available.
  staging: emxx_udc: use list_first_entry_or_null()
  staging/emxx_udc: fix 64-bit warnings
  STAGING: COMEDI: Using kernel types in plx9080.h
  STAGING: COMEDI: Added spaces around binary operators in plx9080.h
  STAGING: COMEDI: Fixed format of comments in plx9080.h
  staging: comedi: comedilib.h: Coding style warning fix for block comments
  staging: comedi: s526: add macros for counter control reg values
  staging: comedi: s526: replace counter mode bitfield struct
  staging: comedi: check for more errors for zero-length write
  staging: comedi: simplify returned errors for comedi_write()
  staging: comedi: return error on "write" if no command set up
  ...
parents 67ad058d 841e3ed9
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.
What: /sys/bus/iio/devices/iio:deviceX/in_allow_async_readout
Date: December 2015
KernelVersion: 4.4
Contact: linux-iio@vger.kernel.org
Description:
By default (value '0'), the capture thread checks for the Conversion
Ready Flag to being set prior to committing a new value to the sample
buffer. This synchronizes the in-chip conversion rate with the
in-driver readout rate at the cost of an additional register read.
Writing '1' will remove the polling for the Conversion Ready Flags to
save the additional i2c transaction, which will improve the bandwidth
available for reading data. However, samples can be occasionally skipped
or repeated, depending on the beat between the capture and conversion
rates.
What: /sys/bus/iio/devices/iio:deviceX/in_shunt_resistor
Date: December 2015
KernelVersion: 4.4
Contact: linux-iio@vger.kernel.org
Description:
The value of the shunt resistor may be known only at runtime fom an
eeprom content read by a client application. This attribute allows to
set its value in ohms.
......@@ -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)
......
......@@ -7,13 +7,18 @@ Required properties:
* "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
- interrupt-names: should contain "INT1" and/or "INT2", the accelerometer's
interrupt line in use.
Example:
mma8453fc@1d {
......@@ -21,4 +26,5 @@ Example:
reg = <0x1d>;
interrupt-parent = <&gpio1>;
interrupts = <5 0>;
interrupt-names = "INT2";
};
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 = <&reg_vcc_3v3_mcu>;
};
......@@ -10,16 +10,28 @@ must be specified.
Required properties:
- compatible: Must be one of the following, depending on the
model:
"mcp3001"
"mcp3002"
"mcp3004"
"mcp3008"
"mcp3201"
"mcp3202"
"mcp3204"
"mcp3208"
"mcp3301"
"mcp3001" (DEPRECATED)
"mcp3002" (DEPRECATED)
"mcp3004" (DEPRECATED)
"mcp3008" (DEPRECATED)
"mcp3201" (DEPRECATED)
"mcp3202" (DEPRECATED)
"mcp3204" (DEPRECATED)
"mcp3208" (DEPRECATED)
"mcp3301" (DEPRECATED)
"microchip,mcp3001"
"microchip,mcp3002"
"microchip,mcp3004"
"microchip,mcp3008"
"microchip,mcp3201"
"microchip,mcp3202"
"microchip,mcp3204"
"microchip,mcp3208"
"microchip,mcp3301"
NOTE: The use of the compatibles with no vendor prefix
is deprecated and only listed because old DT use them.
Examples:
spi_controller {
......
* 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
......
* Palmas general purpose ADC IP block devicetree bindings
Channels list:
0 battery type
1 battery temp NTC (optional current source)
2 GP
3 temp (with ext. diode, optional current source)
4 GP
5 GP
6 VBAT_SENSE
7 VCC_SENSE
8 Backup Battery voltage
9 external charger (VCHG)
10 VBUS
11 DC-DC current probe (how does this work?)
12 internal die temp
13 internal die temp
14 USB ID pin voltage
15 test network
Required properties:
- compatible : Must be "ti,palmas-gpadc".
- #io-channel-cells: Should be set to <1>.
Optional sub-nodes:
ti,channel0-current-microamp: Channel 0 current in uA.
Values are rounded to derive 0uA, 5uA, 15uA, 20uA.
ti,channel3-current-microamp: Channel 3 current in uA.
Values are rounded to derive 0uA, 10uA, 400uA, 800uA.
ti,enable-extended-delay: Enable extended delay.
Example:
pmic {
compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
...
gpadc {
compatible = "ti,palmas-gpadc";
interrupts = <18 0
16 0
17 0>;
#io-channel-cells = <1>;
ti,channel0-current-microamp = <5>;
ti,channel3-current-microamp = <10>;
};
};
...
};
* 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
......
* Texas Instruments' ADS8684 and ADS8688 ADC chip
Required properties:
- compatible: Should be "ti,ads8684" or "ti,ads8688"
- 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:
- vref-supply: The regulator supply for ADC reference voltage
Example:
adc@0 {
compatible = "ti,ads8688";
reg = <0>;
vref-supply = <&vdd_supply>;
spi-max-frequency = <1000000>;
};
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.
......
......@@ -36,6 +36,7 @@ Accelerometers:
- st,lsm303dlm-accel
- st,lsm330-accel
- st,lsm303agr-accel
- st,lis2dh12-accel
Gyroscopes:
- st,l3g4200d-gyro
......
Hi6220 SoC ION
===================================================================
Required properties:
- compatible : "hisilicon,hi6220-ion"
- list of the ION heaps
- heap name : maybe heap_sys_user@0
- heap id : id should be unique in the system.
- heap base : base ddr address of the heap,0 means that
it is dynamic.
- heap size : memory size and 0 means it is dynamic.
- heap type : the heap type of the heap, please also
see the define in ion.h(drivers/staging/android/uapi/ion.h)
-------------------------------------------------------------------
Example:
hi6220-ion {
compatible = "hisilicon,hi6220-ion";
heap_sys_user@0 {
heap-name = "sys_user";
heap-id = <0x0>;
heap-base = <0x0>;
heap-size = <0x0>;
heap-type = "ion_system";
};
heap_sys_contig@0 {
heap-name = "sys_contig";
heap-id = <0x1>;
heap-base = <0x0>;
heap-size = <0x0>;
heap-type = "ion_system_contig";
};
};
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
......@@ -50,8 +66,10 @@ source "drivers/iio/amplifiers/Kconfig"
source "drivers/iio/chemical/Kconfig"
source "drivers/iio/common/Kconfig"
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/
......@@ -16,8 +18,10 @@ obj-y += buffer/
obj-y += chemical/
obj-y += common/
obj-y += dac/
obj-y += dummy/
obj-y += gyro/
obj-y += frequency/
obj-y += health/
obj-y += humidity/
obj-y += imu/
obj-y += light/
......
......@@ -64,7 +64,7 @@ config IIO_ST_ACCEL_3AXIS
help
Say yes here to build support for STMicroelectronics accelerometers:
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
LIS331DLH, LSM303DL, LSM303DLM, LSM330.
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12.
This driver can also be built as a module. If so, these modules
will be created:
......@@ -107,6 +107,35 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
config MMA7455
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config MMA7455_I2C
tristate "Freescale MMA7455L/MMA7456L Accelerometer I2C Driver"
depends on I2C
select MMA7455
select REGMAP_I2C
help
Say yes here to build support for the Freescale MMA7455L and
MMA7456L 3-axis accelerometer.
To compile this driver as a module, choose M here: the module
will be called mma7455_i2c.
config MMA7455_SPI
tristate "Freescale MMA7455L/MMA7456L Accelerometer SPI Driver"
depends on SPI_MASTER
select MMA7455
select REGMAP_SPI
help
Say yes here to build support for the Freescale MMA7455L and
MMA7456L 3-axis accelerometer.
To compile this driver as a module, choose M here: the module
will be called mma7455_spi.
config MMA8452
tristate "Freescale MMA8452Q and similar Accelerometers Driver"
depends on I2C
......@@ -158,6 +187,17 @@ config MXC4005
To compile this driver as a module, choose M. The module will be
called mxc4005.
config MXC6255
tristate "Memsic MXC6255 Orientation Sensing Accelerometer Driver"
depends on I2C
select REGMAP_I2C
help
Say yes here to build support for the Memsic MXC6255 Orientation
Sensing Accelerometer Driver.
To compile this driver as a module, choose M here: the module will be
called mxc6255.
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
......
......@@ -10,6 +10,11 @@ obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_MMA7455) += mma7455_core.o
obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o
obj-$(CONFIG_MMA7455_SPI) += mma7455_spi.o
obj-$(CONFIG_MMA8452) += mma8452.o
obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o
......@@ -17,6 +22,7 @@ obj-$(CONFIG_MMA9551) += mma9551.o
obj-$(CONFIG_MMA9553) += mma9553.o
obj-$(CONFIG_MXC4005) += mxc4005.o
obj-$(CONFIG_MXC6255) += mxc6255.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
......
......@@ -1623,24 +1623,22 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
}
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(dev, "Unable to register iio device\n");
goto err_trigger_unregister;
}
ret = pm_runtime_set_active(dev);
if (ret)
goto err_iio_unregister;
goto err_trigger_unregister;
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(dev, "Unable to register iio device\n");
goto err_trigger_unregister;
}
return 0;
err_iio_unregister:
iio_device_unregister(indio_dev);
err_trigger_unregister:
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
err_buffer_cleanup:
......@@ -1655,12 +1653,12 @@ int bmc150_accel_core_remove(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
pm_runtime_disable(data->dev);
pm_runtime_set_suspended(data->dev);
pm_runtime_put_noidle(data->dev);
iio_device_unregister(indio_dev);
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
iio_triggered_buffer_cleanup(indio_dev);
......
......@@ -1264,25 +1264,23 @@ static int kxcjk1013_probe(struct i2c_client *client,
goto err_trigger_unregister;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
ret = pm_runtime_set_active(&client->dev);
if (ret)
goto err_iio_unregister;
goto err_buffer_cleanup;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
KXCJK1013_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
return 0;
err_iio_unregister:
iio_device_unregister(indio_dev);
err_buffer_cleanup:
if (data->dready_trig)
iio_triggered_buffer_cleanup(indio_dev);
......@@ -1302,12 +1300,12 @@ static int kxcjk1013_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct kxcjk1013_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
iio_device_unregister(indio_dev);
if (data->dready_trig) {
iio_triggered_buffer_cleanup(indio_dev);
iio_trigger_unregister(data->dready_trig);
......
/*
* IIO accel driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
*
* 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.
*/
#ifndef __MMA7455_H
#define __MMA7455_H
extern const struct regmap_config mma7455_core_regmap;
int mma7455_core_probe(struct device *dev, struct regmap *regmap,
const char *name);
int mma7455_core_remove(struct device *dev);
#endif
/*
* IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
*
* 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.
*
* UNSUPPORTED hardware features:
* - 8-bit mode with different scales
* - INT1/INT2 interrupts
* - Offset calibration
* - Events
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "mma7455.h"
#define MMA7455_REG_XOUTL 0x00
#define MMA7455_REG_XOUTH 0x01
#define MMA7455_REG_YOUTL 0x02
#define MMA7455_REG_YOUTH 0x03
#define MMA7455_REG_ZOUTL 0x04
#define MMA7455_REG_ZOUTH 0x05
#define MMA7455_REG_STATUS 0x09
#define MMA7455_STATUS_DRDY BIT(0)
#define MMA7455_REG_WHOAMI 0x0f
#define MMA7455_WHOAMI_ID 0x55
#define MMA7455_REG_MCTL 0x16
#define MMA7455_MCTL_MODE_STANDBY 0x00
#define MMA7455_MCTL_MODE_MEASURE 0x01
#define MMA7455_REG_CTL1 0x18
#define MMA7455_CTL1_DFBW_MASK BIT(7)
#define MMA7455_CTL1_DFBW_125HZ BIT(7)
#define MMA7455_CTL1_DFBW_62_5HZ 0
#define MMA7455_REG_TW 0x1e
/*
* When MMA7455 is used in 10-bit it has a fullscale of -8g
* corresponding to raw value -512. The userspace interface
* uses m/s^2 and we declare micro units.
* So scale factor is given by:
* g * 8 * 1e6 / 512 = 153228.90625, with g = 9.80665
*/
#define MMA7455_10BIT_SCALE 153229
struct mma7455_data {
struct regmap *regmap;
struct device *dev;
};
static int mma7455_drdy(struct mma7455_data *mma7455)
{
unsigned int reg;
int tries = 3;
int ret;
while (tries-- > 0) {
ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, &reg);
if (ret)
return ret;
if (reg & MMA7455_STATUS_DRDY)
return 0;
msleep(20);
}
dev_warn(mma7455->dev, "data not ready\n");
return -EIO;
}
static irqreturn_t mma7455_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct mma7455_data *mma7455 = iio_priv(indio_dev);
u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
int ret;
ret = mma7455_drdy(mma7455);
if (ret)
goto done;
ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
sizeof(__le16) * 3);
if (ret)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int mma7455_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mma7455_data *mma7455 = iio_priv(indio_dev);
unsigned int reg;
__le16 data;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
ret = mma7455_drdy(mma7455);
if (ret)
return ret;
ret = regmap_bulk_read(mma7455->regmap, chan->address, &data,
sizeof(data));
if (ret)
return ret;
*val = sign_extend32(le16_to_cpu(data), 9);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = MMA7455_10BIT_SCALE;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, &reg);
if (ret)
return ret;
if (reg & MMA7455_CTL1_DFBW_MASK)
*val = 250;
else
*val = 125;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int mma7455_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct mma7455_data *mma7455 = iio_priv(indio_dev);
int i;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
if (val == 250 && val2 == 0)
i = MMA7455_CTL1_DFBW_125HZ;
else if (val == 125 && val2 == 0)
i = MMA7455_CTL1_DFBW_62_5HZ;
else
return -EINVAL;
return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1,
MMA7455_CTL1_DFBW_MASK, i);
case IIO_CHAN_INFO_SCALE:
/* In 10-bit mode there is only one scale available */
if (val == 0 && val2 == MMA7455_10BIT_SCALE)
return 0;
break;
}
return -EINVAL;
}
static IIO_CONST_ATTR(sampling_frequency_available, "125 250");
static struct attribute *mma7455_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group mma7455_group = {
.attrs = mma7455_attributes,
};
static const struct iio_info mma7455_info = {
.attrs = &mma7455_group,
.read_raw = mma7455_read_raw,
.write_raw = mma7455_write_raw,
.driver_module = THIS_MODULE,
};
#define MMA7455_CHANNEL(axis, idx) { \
.type = IIO_ACCEL, \
.modified = 1, \
.address = MMA7455_REG_##axis##OUTL,\
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
.realbits = 10, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
}
static const struct iio_chan_spec mma7455_channels[] = {
MMA7455_CHANNEL(X, 0),
MMA7455_CHANNEL(Y, 1),
MMA7455_CHANNEL(Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const unsigned long mma7455_scan_masks[] = {0x7, 0};
const struct regmap_config mma7455_core_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MMA7455_REG_TW,
};
EXPORT_SYMBOL_GPL(mma7455_core_regmap);
int mma7455_core_probe(struct device *dev, struct regmap *regmap,
const char *name)
{
struct mma7455_data *mma7455;
struct iio_dev *indio_dev;
unsigned int reg;
int ret;
ret = regmap_read(regmap, MMA7455_REG_WHOAMI, &reg);
if (ret) {
dev_err(dev, "unable to read reg\n");
return ret;
}
if (reg != MMA7455_WHOAMI_ID) {
dev_err(dev, "device id mismatch\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(dev, sizeof(*mma7455));
if (!indio_dev)
return -ENOMEM;
dev_set_drvdata(dev, indio_dev);
mma7455 = iio_priv(indio_dev);
mma7455->regmap = regmap;
mma7455->dev = dev;
indio_dev->info = &mma7455_info;
indio_dev->name = name;
indio_dev->dev.parent = dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mma7455_channels;
indio_dev->num_channels = ARRAY_SIZE(mma7455_channels);
indio_dev->available_scan_masks = mma7455_scan_masks;
regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
MMA7455_MCTL_MODE_MEASURE);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
mma7455_trigger_handler, NULL);
if (ret) {
dev_err(dev, "unable to setup triggered buffer\n");
return ret;
}
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(dev, "unable to register device\n");
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(mma7455_core_probe);
int mma7455_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct mma7455_data *mma7455 = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
MMA7455_MCTL_MODE_STANDBY);
return 0;
}
EXPORT_SYMBOL_GPL(mma7455_core_remove);
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver");
MODULE_LICENSE("GPL v2");
/*
* IIO accel I2C driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
*
* 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/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "mma7455.h"
static int mma7455_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regmap *regmap;
const char *name = NULL;
regmap = devm_regmap_init_i2c(i2c, &mma7455_core_regmap);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
if (id)
name = id->name;
return mma7455_core_probe(&i2c->dev, regmap, name);
}
static int mma7455_i2c_remove(struct i2c_client *i2c)
{
return mma7455_core_remove(&i2c->dev);
}
static const struct i2c_device_id mma7455_i2c_ids[] = {
{ "mma7455", 0 },
{ "mma7456", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids);
static struct i2c_driver mma7455_i2c_driver = {
.probe = mma7455_i2c_probe,
.remove = mma7455_i2c_remove,
.id_table = mma7455_i2c_ids,
.driver = {
.name = "mma7455-i2c",
},
};
module_i2c_driver(mma7455_i2c_driver);
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver");
MODULE_LICENSE("GPL v2");
/*
* IIO accel SPI driver for Freescale MMA7455L 3-axis 10-bit accelerometer
* Copyright 2015 Joachim Eastwood <manabian@gmail.com>
*
* 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/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "mma7455.h"
static int mma7455_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &mma7455_core_regmap);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return mma7455_core_probe(&spi->dev, regmap, id->name);
}
static int mma7455_spi_remove(struct spi_device *spi)
{
return mma7455_core_remove(&spi->dev);
}
static const struct spi_device_id mma7455_spi_ids[] = {
{ "mma7455", 0 },
{ "mma7456", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, mma7455_spi_ids);
static struct spi_driver mma7455_spi_driver = {
.probe = mma7455_spi_probe,
.remove = mma7455_spi_remove,
.id_table = mma7455_spi_ids,
.driver = {
.name = "mma7455-spi",
},
};
module_spi_driver(mma7455_spi_driver);
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver");
MODULE_LICENSE("GPL v2");
......@@ -29,6 +29,7 @@
#include <linux/iio/events.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
......@@ -57,7 +58,6 @@
#define MMA8452_FF_MT_COUNT 0x18
#define MMA8452_TRANSIENT_CFG 0x1d
#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
#define MMA8452_TRANSIENT_SRC 0x1e
#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
......@@ -143,6 +143,13 @@ struct mma_chip_info {
u8 ev_count;
};
enum {
idx_x,
idx_y,
idx_z,
idx_ts,
};
static int mma8452_drdy(struct mma8452_data *data)
{
int tries = 150;
......@@ -816,31 +823,31 @@ static struct attribute_group mma8452_event_attribute_group = {
}
static const struct iio_chan_spec mma8452_channels[] = {
MMA8452_CHANNEL(X, 0, 12),
MMA8452_CHANNEL(Y, 1, 12),
MMA8452_CHANNEL(Z, 2, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
MMA8452_CHANNEL(X, idx_x, 12),
MMA8452_CHANNEL(Y, idx_y, 12),
MMA8452_CHANNEL(Z, idx_z, 12),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
static const struct iio_chan_spec mma8453_channels[] = {
MMA8452_CHANNEL(X, 0, 10),
MMA8452_CHANNEL(Y, 1, 10),
MMA8452_CHANNEL(Z, 2, 10),
IIO_CHAN_SOFT_TIMESTAMP(3),
MMA8452_CHANNEL(X, idx_x, 10),
MMA8452_CHANNEL(Y, idx_y, 10),
MMA8452_CHANNEL(Z, idx_z, 10),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
static const struct iio_chan_spec mma8652_channels[] = {
MMA8652_CHANNEL(X, 0, 12),
MMA8652_CHANNEL(Y, 1, 12),
MMA8652_CHANNEL(Z, 2, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
MMA8652_CHANNEL(X, idx_x, 12),
MMA8652_CHANNEL(Y, idx_y, 12),
MMA8652_CHANNEL(Z, idx_z, 12),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
static const struct iio_chan_spec mma8653_channels[] = {
MMA8652_CHANNEL(X, 0, 10),
MMA8652_CHANNEL(Y, 1, 10),
MMA8652_CHANNEL(Z, 2, 10),
IIO_CHAN_SOFT_TIMESTAMP(3),
MMA8652_CHANNEL(X, idx_x, 10),
MMA8652_CHANNEL(Y, idx_y, 10),
MMA8652_CHANNEL(Z, idx_z, 10),
IIO_CHAN_SOFT_TIMESTAMP(idx_ts),
};
enum {
......@@ -1130,13 +1137,21 @@ static int mma8452_probe(struct i2c_client *client,
MMA8452_INT_FF_MT;
int enabled_interrupts = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT;
int irq2;
/* Assume wired to INT1 pin */
ret = i2c_smbus_write_byte_data(client,
MMA8452_CTRL_REG5,
supported_interrupts);
if (ret < 0)
return ret;
irq2 = of_irq_get_byname(client->dev.of_node, "INT2");
if (irq2 == client->irq) {
dev_dbg(&client->dev, "using interrupt line INT2\n");
} else {
ret = i2c_smbus_write_byte_data(client,
MMA8452_CTRL_REG5,
supported_interrupts);
if (ret < 0)
return ret;
dev_dbg(&client->dev, "using interrupt line INT1\n");
}
ret = i2c_smbus_write_byte_data(client,
MMA8452_CTRL_REG4,
......
......@@ -495,25 +495,23 @@ static int mma9551_probe(struct i2c_client *client,
if (ret < 0)
goto out_poweroff;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto out_poweroff;
}
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
goto out_iio_unregister;
goto out_poweroff;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
MMA9551_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto out_poweroff;
}
return 0;
out_iio_unregister:
iio_device_unregister(indio_dev);
out_poweroff:
mma9551_set_device_state(client, false);
......@@ -525,11 +523,12 @@ static int mma9551_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma9551_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
iio_device_unregister(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
mutex_unlock(&data->mutex);
......
......@@ -1133,27 +1133,24 @@ static int mma9553_probe(struct i2c_client *client,
}
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto out_poweroff;
}
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
goto out_iio_unregister;
goto out_poweroff;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
MMA9551_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto out_poweroff;
}
dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
return 0;
out_iio_unregister:
iio_device_unregister(indio_dev);
out_poweroff:
mma9551_set_device_state(client, false);
return ret;
......@@ -1164,11 +1161,12 @@ static int mma9553_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma9553_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
iio_device_unregister(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
mutex_unlock(&data->mutex);
......
/*
* MXC6255 - MEMSIC orientation sensing accelerometer
*
* Copyright (c) 2015, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* IIO driver for MXC6255 (7-bit I2C slave address 0x15).
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/iio/iio.h>
#include <linux/delay.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/iio/sysfs.h>
#define MXC6255_DRV_NAME "mxc6255"
#define MXC6255_REGMAP_NAME "mxc6255_regmap"
#define MXC6255_REG_XOUT 0x00
#define MXC6255_REG_YOUT 0x01
#define MXC6255_REG_CHIP_ID 0x08
#define MXC6255_CHIP_ID 0x05
/*
* MXC6255 has only one measurement range: +/- 2G.
* The acceleration output is an 8-bit value.
*
* Scale is calculated as follows:
* (2 + 2) * 9.80665 / (2^8 - 1) = 0.153829
*
* Scale value for +/- 2G measurement range
*/
#define MXC6255_SCALE 153829
enum mxc6255_axis {
AXIS_X,
AXIS_Y,
};
struct mxc6255_data {
struct i2c_client *client;
struct regmap *regmap;
};
static int mxc6255_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mxc6255_data *data = iio_priv(indio_dev);
unsigned int reg;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = regmap_read(data->regmap, chan->address, &reg);
if (ret < 0) {
dev_err(&data->client->dev,
"Error reading reg %lu\n", chan->address);
return ret;
}
*val = sign_extend32(reg, 7);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = MXC6255_SCALE;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static const struct iio_info mxc6255_info = {
.driver_module = THIS_MODULE,
.read_raw = mxc6255_read_raw,
};
#define MXC6255_CHANNEL(_axis, reg) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.address = reg, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mxc6255_channels[] = {
MXC6255_CHANNEL(X, MXC6255_REG_XOUT),
MXC6255_CHANNEL(Y, MXC6255_REG_YOUT),
};
static bool mxc6255_is_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MXC6255_REG_XOUT:
case MXC6255_REG_YOUT:
case MXC6255_REG_CHIP_ID:
return true;
default:
return false;
}
}
static const struct regmap_config mxc6255_regmap_config = {
.name = MXC6255_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
.readable_reg = mxc6255_is_readable_reg,
};
static int mxc6255_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mxc6255_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
unsigned int chip_id;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
regmap = devm_regmap_init_i2c(client, &mxc6255_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Error initializing regmap\n");
return PTR_ERR(regmap);
}
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->regmap = regmap;
indio_dev->name = MXC6255_DRV_NAME;
indio_dev->dev.parent = &client->dev;
indio_dev->channels = mxc6255_channels;
indio_dev->num_channels = ARRAY_SIZE(mxc6255_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mxc6255_info;
ret = regmap_read(data->regmap, MXC6255_REG_CHIP_ID, &chip_id);
if (ret < 0) {
dev_err(&client->dev, "Error reading chip id %d\n", ret);
return ret;
}
if (chip_id != MXC6255_CHIP_ID) {
dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
return -ENODEV;
}
dev_dbg(&client->dev, "Chip id %x\n", chip_id);
ret = devm_iio_device_register(&client->dev, indio_dev);
if (ret < 0) {
dev_err(&client->dev, "Could not register IIO device\n");
return ret;
}
return 0;
}
static const struct acpi_device_id mxc6255_acpi_match[] = {
{"MXC6255", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
static const struct i2c_device_id mxc6255_id[] = {
{"mxc6255", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, mxc6255_id);
static struct i2c_driver mxc6255_driver = {
.driver = {
.name = MXC6255_DRV_NAME,
.acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
},
.probe = mxc6255_probe,
.id_table = mxc6255_id,
};
module_i2c_driver(mxc6255_driver);
MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
MODULE_DESCRIPTION("MEMSIC MXC6255 orientation sensing accelerometer driver");
MODULE_LICENSE("GPL v2");
......@@ -27,6 +27,7 @@
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel"
#define LIS2DH12_ACCEL_DEV_NAME "lis2dh12_accel"
/**
* struct st_sensors_platform_data - default accel platform data
......
......@@ -232,6 +232,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
[3] = LSM330DL_ACCEL_DEV_NAME,
[4] = LSM330DLC_ACCEL_DEV_NAME,
[5] = LSM303AGR_ACCEL_DEV_NAME,
[6] = LIS2DH12_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
......
......@@ -72,6 +72,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lsm303agr-accel",
.data = LSM303AGR_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2dh12-accel",
.data = LIS2DH12_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -121,6 +125,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{ LIS2DH12_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
......
......@@ -58,6 +58,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
{ LSM303AGR_ACCEL_DEV_NAME },
{ LIS2DH12_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
......
......@@ -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
......@@ -275,6 +294,14 @@ config NAU7802
To compile this driver as a module, choose M here: the
module will be called nau7802.
config PALMAS_GPADC
tristate "TI Palmas General Purpose ADC"
depends on MFD_PALMAS
help
Palmas series pmic chip by Texas Instruments (twl6035/6037)
is used in smartphones and tablets and supports a 16 channel
general purpose ADC.
config QCOM_SPMI_IADC
tristate "Qualcomm SPMI PMIC current ADC"
depends on SPMI
......@@ -324,15 +351,25 @@ 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.
config TI_ADS8688
tristate "Texas Instruments ADS8688"
depends on SPI && OF
help
If you say yes here you get support for Texas Instruments ADS8684 and
and ADS8688 ADC chips
This driver can also be built as a module. If so, the module will be
called ti-ads8688.
config TI_AM335X_ADC
tristate "TI's AM335X ADC driver"
depends on MFD_TI_AM335X_TSCADC
......
......@@ -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
......@@ -27,11 +29,13 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
......
......@@ -478,10 +478,9 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
*val2 = st->
scale_avail[(st->conf >> 8) & 0x7][1];
return IIO_VAL_INT_PLUS_NANO;
} else {
/* 1170mV / 2^23 * 6 */
scale_uv = (1170ULL * 1000000000ULL * 6ULL);
}
/* 1170mV / 2^23 * 6 */
scale_uv = (1170ULL * 1000000000ULL * 6ULL);
break;
case IIO_TEMP:
/* 1170mV / 0.81 mV/C / 2^23 */
......
......@@ -742,7 +742,7 @@ static int at91_adc_of_get_resolution(struct at91_adc_state *st,
return count;
}
resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL);
resolutions = kmalloc_array(count, sizeof(*resolutions), GFP_KERNEL);
if (!resolutions)
return -ENOMEM;
......
This diff is collapsed.
This diff is collapsed.
......@@ -354,6 +354,7 @@ static int mcp320x_remove(struct spi_device *spi)
#if defined(CONFIG_OF)
static const struct of_device_id mcp320x_dt_ids[] = {
/* NOTE: The use of compatibles with no vendor prefix is deprecated. */
{
.compatible = "mcp3001",
.data = &mcp320x_chip_infos[mcp3001],
......@@ -381,6 +382,33 @@ static const struct of_device_id mcp320x_dt_ids[] = {
}, {
.compatible = "mcp3301",
.data = &mcp320x_chip_infos[mcp3301],
}, {
.compatible = "microchip,mcp3001",
.data = &mcp320x_chip_infos[mcp3001],
}, {
.compatible = "microchip,mcp3002",
.data = &mcp320x_chip_infos[mcp3002],
}, {
.compatible = "microchip,mcp3004",
.data = &mcp320x_chip_infos[mcp3004],
}, {
.compatible = "microchip,mcp3008",
.data = &mcp320x_chip_infos[mcp3008],
}, {
.compatible = "microchip,mcp3201",
.data = &mcp320x_chip_infos[mcp3201],
}, {
.compatible = "microchip,mcp3202",
.data = &mcp320x_chip_infos[mcp3202],
}, {
.compatible = "microchip,mcp3204",
.data = &mcp320x_chip_infos[mcp3204],
}, {
.compatible = "microchip,mcp3208",
.data = &mcp320x_chip_infos[mcp3208],
}, {
.compatible = "microchip,mcp3301",
.data = &mcp320x_chip_infos[mcp3301],
}, {
}
};
......
......@@ -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 },
......
This diff is collapsed.
/*
* 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);
......
This diff is collapsed.
......@@ -803,7 +803,7 @@ static int xadc_preenable(struct iio_dev *indio_dev)
return ret;
}
static struct iio_buffer_setup_ops xadc_buffer_ops = {
static const struct iio_buffer_setup_ops xadc_buffer_ops = {
.preenable = &xadc_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
......
......@@ -9,6 +9,26 @@ config IIO_BUFFER_CB
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_BUFFER_DMA
tristate
help
Provides the generic IIO DMA buffer infrastructure that can be used by
drivers for devices with DMA support to implement the IIO buffer.
Should be selected by drivers that want to use the generic DMA buffer
infrastructure.
config IIO_BUFFER_DMAENGINE
tristate
select IIO_BUFFER_DMA
help
Provides a bonding of the generic IIO DMA buffer infrastructure with the
DMAengine framework. This can be used by converter drivers with a DMA port
connected to an external DMA controller which is supported by the
DMAengine framework.
Should be selected by drivers that want to use this functionality.
config IIO_KFIFO_BUF
tristate "Industrial I/O buffering based on kfifo"
help
......
......@@ -4,5 +4,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o
obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o
obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
This diff is collapsed.
/*
* Copyright 2014-2015 Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer-dma.h>
#include <linux/iio/buffer-dmaengine.h>
/*
* The IIO DMAengine buffer combines the generic IIO DMA buffer infrastructure
* with the DMAengine framework. The generic IIO DMA buffer infrastructure is
* used to manage the buffer memory and implement the IIO buffer operations
* while the DMAengine framework is used to perform the DMA transfers. Combined
* this results in a device independent fully functional DMA buffer
* implementation that can be used by device drivers for peripherals which are
* connected to a DMA controller which has a DMAengine driver implementation.
*/
struct dmaengine_buffer {
struct iio_dma_buffer_queue queue;
struct dma_chan *chan;
struct list_head active;
size_t align;
size_t max_size;
};
static struct dmaengine_buffer *iio_buffer_to_dmaengine_buffer(
struct iio_buffer *buffer)
{
return container_of(buffer, struct dmaengine_buffer, queue.buffer);
}
static void iio_dmaengine_buffer_block_done(void *data)
{
struct iio_dma_buffer_block *block = data;
unsigned long flags;
spin_lock_irqsave(&block->queue->list_lock, flags);
list_del(&block->head);
spin_unlock_irqrestore(&block->queue->list_lock, flags);
iio_dma_buffer_block_done(block);
}
static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
struct iio_dma_buffer_block *block)
{
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(&queue->buffer);
struct dma_async_tx_descriptor *desc;
dma_cookie_t cookie;
block->bytes_used = min(block->size, dmaengine_buffer->max_size);
block->bytes_used = rounddown(block->bytes_used,
dmaengine_buffer->align);
desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
block->phys_addr, block->bytes_used, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!desc)
return -ENOMEM;
desc->callback = iio_dmaengine_buffer_block_done;
desc->callback_param = block;
cookie = dmaengine_submit(desc);
if (dma_submit_error(cookie))
return dma_submit_error(cookie);
spin_lock_irq(&dmaengine_buffer->queue.list_lock);
list_add_tail(&block->head, &dmaengine_buffer->active);
spin_unlock_irq(&dmaengine_buffer->queue.list_lock);
dma_async_issue_pending(dmaengine_buffer->chan);
return 0;
}
static void iio_dmaengine_buffer_abort(struct iio_dma_buffer_queue *queue)
{
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(&queue->buffer);
dmaengine_terminate_all(dmaengine_buffer->chan);
/* FIXME: There is a slight chance of a race condition here.
* dmaengine_terminate_all() does not guarantee that all transfer
* callbacks have finished running. Need to introduce a
* dmaengine_terminate_all_sync().
*/
iio_dma_buffer_block_list_abort(queue, &dmaengine_buffer->active);
}
static void iio_dmaengine_buffer_release(struct iio_buffer *buf)
{
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(buf);
iio_dma_buffer_release(&dmaengine_buffer->queue);
kfree(dmaengine_buffer);
}
static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
.read_first_n = iio_dma_buffer_read,
.set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum,
.set_length = iio_dma_buffer_set_length,
.request_update = iio_dma_buffer_request_update,
.enable = iio_dma_buffer_enable,
.disable = iio_dma_buffer_disable,
.data_available = iio_dma_buffer_data_available,
.release = iio_dmaengine_buffer_release,
.modes = INDIO_BUFFER_HARDWARE,
.flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK,
};
static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = {
.submit = iio_dmaengine_buffer_submit_block,
.abort = iio_dmaengine_buffer_abort,
};
/**
* iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
* @dev: Parent device for the buffer
* @channel: DMA channel name, typically "rx".
*
* This allocates a new IIO buffer which internally uses the DMAengine framework
* to perform its transfers. The parent device will be used to request the DMA
* channel.
*
* Once done using the buffer iio_dmaengine_buffer_free() should be used to
* release it.
*/
struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
const char *channel)
{
struct dmaengine_buffer *dmaengine_buffer;
unsigned int width, src_width, dest_width;
struct dma_slave_caps caps;
struct dma_chan *chan;
int ret;
dmaengine_buffer = kzalloc(sizeof(*dmaengine_buffer), GFP_KERNEL);
if (!dmaengine_buffer)
return ERR_PTR(-ENOMEM);
chan = dma_request_slave_channel_reason(dev, channel);
if (IS_ERR(chan)) {
ret = PTR_ERR(chan);
goto err_free;
}
ret = dma_get_slave_caps(chan, &caps);
if (ret < 0)
goto err_free;
/* Needs to be aligned to the maximum of the minimums */
if (caps.src_addr_widths)
src_width = __ffs(caps.src_addr_widths);
else
src_width = 1;
if (caps.dst_addr_widths)
dest_width = __ffs(caps.dst_addr_widths);
else
dest_width = 1;
width = max(src_width, dest_width);
INIT_LIST_HEAD(&dmaengine_buffer->active);
dmaengine_buffer->chan = chan;
dmaengine_buffer->align = width;
dmaengine_buffer->max_size = dma_get_max_seg_size(chan->device->dev);
iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev,
&iio_dmaengine_default_ops);
dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops;
return &dmaengine_buffer->queue.buffer;
err_free:
kfree(dmaengine_buffer);
return ERR_PTR(ret);
}
EXPORT_SYMBOL(iio_dmaengine_buffer_alloc);
/**
* iio_dmaengine_buffer_free() - Free dmaengine buffer
* @buffer: Buffer to free
*
* Frees a buffer previously allocated with iio_dmaengine_buffer_alloc().
*/
void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
{
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(buffer);
iio_dma_buffer_exit(&dmaengine_buffer->queue);
dma_release_channel(dmaengine_buffer->chan);
iio_buffer_put(buffer);
}
EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free);
......@@ -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
/*
* 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_get_measurement(struct vz89x_data *data)
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{
struct i2c_client *client = data->client;
struct i2c_msg msg[2];
int ret;
int i;
u8 buf[3] = { cmd, 0, 0};
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 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);
ret = i2c_smbus_write_word_data(data->client,
VZ89X_REG_MEASUREMENT, 0);
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(data->client);
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;
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 0;
ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
if (ret < 0)
return 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;
......
......@@ -18,9 +18,6 @@
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
#define ST_SENSORS_WAI_ADDRESS 0x0f
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
......
This diff is collapsed.
#
# Makefile for the IIO Dummy Driver
#
obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
iio_dummy-y := iio_simple_dummy.o
iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o
iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
obj-$(CONFIG_HI6220_ION) += hi6220_ion.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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