Commit d5bd1eba authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

Merge tag 'iio-for-4.9a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into work-testing

Jonathan writes:

First round of new features, device support and cleanups for IIO in the 4.9 cycle.

Device support

* ak8974
  - New driver and bindings for this 2009 vintage magnetometer (it was very
    popular back then!)
* atlas-ph-sensor
  -  ORP sensor support(I had to look up what one of these was)
* cio-dac
  - New driver for Measurement Computing DAC boards
* dmard06
  - New driver for Domintech DMARDO6 accelerometer. Also vendor prefix.
* dmard09
  - New driver for Domintech DMARD09 accelerometer.
* maxim-thermocouple
  - max6675 and max31855 new driver
* mt6577 auxdac
  - new driver for this Mediatek chip mt2701, mt6577 and mt8173 have this
    hardware.
* ti-adc161s626
  - new driver for this TI single channel differential ADC.
* vcnl4000
  - support vcnl4010 and vcnl4020 which are compatible for all features
    currently supported by this driver.

New features

* Core
  - Allow retrieving of underlying iio_dev from a callback buffer handle.
    This is needed to allow client drivers to perform operations such as
    configuring the trigger used.
* hid-sensors
  - asynchronous resume support to avoid really long resume times.
* kxcjk-1013
  - add the mysterious KIOX000A ACPI id seen in the wild.
* Tools
  - lsiio now enumerates processed as well as raw channels.

Cleanup

* ad7298
  - use iio_device_claim_direct_mode and friends to simplify locking around
    mode switching and drop some boilerplate.
* ad7793
  - use iio_device_claim_direct_mode and friends to simplify locking around
    mode switching and drop some boilerplate.
* ade7854
  - checkpatch fixups (alignment of parameters)
* atlas-ph-sensor
  - use iio_device_claim_direct_mode and friends to simplify locking around
    mode switching and drop some boilerplate.
  - Switch to REGCACHE_NONE as there are no useful register to cache.
* bma180
  - use iio_device_claim_direct_mode and friends to simplify locking around
    mode switching and drop some boilerplate.
* hdc100x
  - Add mention of the HDC1000 and HDC1008 to the Kconfig help text.
* isl29018
  - Add driver specific prefixes to defines and function names.
  - Remove excessive logging.
  - Drop newlines which add nothing to readability.
  - General tidying up of comments.
  - Drop I2C_CLASS_HWMON as irrelevant to driver.
* isl29028
  - Add driver specific prefixes to defines, enums and function names.
  - Drop comma's from available attribute output as not ABI compliant.
  - Drop I2C_CLASS_HWMON as irrelevant to driver.
* kxsd9
  - devicetree bindings.
* mag3110
  - This one wasn't locking to protect against mode switches during
    raw_reads.  Use the iio_claim_direct_mode function to fix this buglet.
* maxim-theromcouple
  - Fix missing selects for triggered buffer support in Kconfig.
* nau7802
  - Use complete instead of complete_all as only one completion at a time.
* sx9500
  - Use complete instead of complete_all as only one completion at a time.
* us5182d
  - Add a missing error code asignment instead of checking the result of
    an already checked statement.
* vcnl4000
  - Use BIT macro where appropriate.
  - Refactor return codes in read_raw callback.
  - Add some missing locking for concurrent accesses to the device.
parents 1d9e3a07 87557ade
......@@ -38,6 +38,7 @@ dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
dallas,ds75 Digital Thermometer and Thermostat
dlg,da9053 DA9053: flexible system level PMIC with multicore support
dlg,da9063 DA9063: system PMIC for quad-core application processors
domintech,dmard09 DMARD09: 3-axis Accelerometer
epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE
epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
......
Device tree bindings for Domintech DMARD05, DMARD06, DMARD07 accelerometers
Required properties:
- compatible : Should be "domintech,dmard05"
or "domintech,dmard06"
or "domintech,dmard07"
- reg : I2C address of the chip. Should be 0x1c
Example:
&i2c1 {
/* ... */
accelerometer@1c {
compatible = "domintech,dmard06";
reg = <0x1c>;
};
/* ... */
};
Kionix KXSD9 Accelerometer device tree bindings
Required properties:
- compatible: should be set to "kionix,kxsd9"
- reg: i2c slave address
Optional properties:
- vdd-supply: The input supply for VDD
- iovdd-supply: The input supply for IOVDD
- interrupts: The movement detection interrupt
- mount-matrix: See mount-matrix.txt
Example:
kxsd9@18 {
compatible = "kionix,kxsd9";
reg = <0x18>;
interrupt-parent = <&foo>;
interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
iovdd-supply = <&bar>;
vdd-supply = <&baz>;
};
MediaTek AUXADC
* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
===============
The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
......@@ -10,12 +10,20 @@ Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
for the Thermal Controller which holds a phandle to the AUXADC.
Required properties:
- compatible: Must be "mediatek,mt8173-auxadc"
- reg: Address range of the AUXADC unit
- compatible: Should be one of:
- "mediatek,mt2701-auxadc": For MT2701 family of SoCs
- "mediatek,mt8173-auxadc": For MT8173 family of SoCs
- reg: Address range of the AUXADC unit.
- clocks: Should contain a clock specifier for each entry in clock-names
- clock-names: Should contain "main".
- #io-channel-cells: Should be 1, see ../iio-bindings.txt
Example:
auxadc: auxadc@11001000 {
compatible = "mediatek,mt8173-auxadc";
auxadc: adc@11001000 {
compatible = "mediatek,mt2701-auxadc";
reg = <0 0x11001000 0 0x1000>;
clocks = <&pericfg CLK_PERI_AUXADC>;
clock-names = "main";
#io-channel-cells = <1>;
};
* Texas Instruments ADC141S626 and ADC161S626 chips
Required properties:
- compatible: Should be "ti,adc141s626" or "ti,adc161s626"
- reg: spi chip select number for the device
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc161s626";
reg = <0>;
spi-max-frequency = <4300000>;
};
* Atlas Scientific ORP-SM OEM sensor
https://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf
Required properties:
- compatible: must be "atlas,orp-sm"
- 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:
atlas@66 {
compatible = "atlas,orp-sm";
reg = <0x66>;
interrupt-parent = <&gpio1>;
interrupts = <16 2>;
};
* Asahi Kasei AK8974 magnetometer sensor
Required properties:
- compatible : should be "asahi-kasei,ak8974"
- reg : the I2C address of the magnetometer
Optional properties:
- avdd-supply: regulator supply for the analog voltage
(see regulator/regulator.txt)
- dvdd-supply: regulator supply for the digital voltage
(see regulator/regulator.txt)
- interrupts: data ready (DRDY) and interrupt (INT1) lines
from the chip, the DRDY interrupt must be placed first.
The interrupts can be triggered on rising or falling
edges alike.
- mount-matrix: an optional 3x3 mounting rotation matrix
Example:
ak8974@0f {
compatible = "asahi-kasei,ak8974";
reg = <0x0f>;
avdd-supply = <&foo_reg>;
dvdd-supply = <&bar_reg>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>,
<1 IRQ_TYPE_EDGE_RISING>;
};
Maxim thermocouple support
* https://datasheets.maximintegrated.com/en/ds/MAX6675.pdf
* https://datasheets.maximintegrated.com/en/ds/MAX31855.pdf
Required properties:
- compatible: must be "maxim,max31855" or "maxim,max6675"
- reg: SPI chip select number for the device
- spi-max-frequency: must be 4300000
- spi-cpha: must be defined for max6675 to enable SPI mode 1
Refer to spi/spi-bus.txt for generic SPI slave bindings.
Example:
max31855@0 {
compatible = "maxim,max31855";
reg = <0>;
spi-max-frequency = <4300000>;
};
......@@ -75,6 +75,7 @@ digilent Diglent, Inc.
dlg Dialog Semiconductor
dlink D-Link Corporation
dmo Data Modul AG
domintech Domintech Co., Ltd.
dptechnics DPTechnics
dragino Dragino Technology Co., Limited
ea Embedded Artists AB
......
......@@ -1965,6 +1965,13 @@ S: Maintained
F: drivers/media/i2c/as3645a.c
F: include/media/i2c/as3645a.h
ASAHI KASEI AK8974 DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-iio@vger.kernel.org
W: http://www.akm.com/
S: Supported
F: drivers/iio/magnetometer/ak8974.c
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <george.joseph@fairview5.com>
L: linux-hwmon@vger.kernel.org
......@@ -7497,6 +7504,12 @@ L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/potentiometer/mcp4531.c
MEASUREMENT COMPUTING CIO-DAC IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/dac/cio-dac.c
MEDIA DRIVERS FOR RENESAS - FCP
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
......
......@@ -50,6 +50,27 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
config DMARD06
tristate "Domintech DMARD06 Digital Accelerometer Driver"
depends on OF || COMPILE_TEST
depends on I2C
help
Say yes here to build support for the Domintech low-g tri-axial
digital accelerometers: DMARD05, DMARD06, DMARD07.
To compile this driver as a module, choose M here: the
module will be called dmard06.
config DMARD09
tristate "Domintech DMARD09 3-axis Accelerometer Driver"
depends on I2C
help
Say yes here to get support for the Domintech DMARD09 3-axis
accelerometer.
Choosing M will build the driver as a module. If so, the module
will be called dmard09.
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
......
......@@ -8,6 +8,8 @@ obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_DMARD06) += dmard06.o
obj-$(CONFIG_DMARD09) += dmard09.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
......
......@@ -469,13 +469,14 @@ static int bma180_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&data->mutex);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&data->mutex);
return -EBUSY;
}
ret = bma180_get_data_reg(data, chan->scan_index);
mutex_unlock(&data->mutex);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = sign_extend32(ret >> chan->scan_type.shift,
......
/*
* IIO driver for Domintech DMARD06 accelerometer
*
* Copyright (C) 2016 Aleksei Mamlin <mamlinav@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#define DMARD06_DRV_NAME "dmard06"
/* Device data registers */
#define DMARD06_CHIP_ID_REG 0x0f
#define DMARD06_TOUT_REG 0x40
#define DMARD06_XOUT_REG 0x41
#define DMARD06_YOUT_REG 0x42
#define DMARD06_ZOUT_REG 0x43
#define DMARD06_CTRL1_REG 0x44
/* Device ID value */
#define DMARD05_CHIP_ID 0x05
#define DMARD06_CHIP_ID 0x06
#define DMARD07_CHIP_ID 0x07
/* Device values */
#define DMARD05_AXIS_SCALE_VAL 15625
#define DMARD06_AXIS_SCALE_VAL 31250
#define DMARD06_TEMP_CENTER_VAL 25
#define DMARD06_SIGN_BIT 7
/* Device power modes */
#define DMARD06_MODE_NORMAL 0x27
#define DMARD06_MODE_POWERDOWN 0x00
/* Device channels */
#define DMARD06_ACCEL_CHANNEL(_axis, _reg) { \
.type = IIO_ACCEL, \
.address = _reg, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.modified = 1, \
}
#define DMARD06_TEMP_CHANNEL(_reg) { \
.type = IIO_TEMP, \
.address = _reg, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET), \
}
struct dmard06_data {
struct i2c_client *client;
u8 chip_id;
};
static const struct iio_chan_spec dmard06_channels[] = {
DMARD06_ACCEL_CHANNEL(X, DMARD06_XOUT_REG),
DMARD06_ACCEL_CHANNEL(Y, DMARD06_YOUT_REG),
DMARD06_ACCEL_CHANNEL(Z, DMARD06_ZOUT_REG),
DMARD06_TEMP_CHANNEL(DMARD06_TOUT_REG),
};
static int dmard06_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct dmard06_data *dmard06 = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_byte_data(dmard06->client,
chan->address);
if (ret < 0) {
dev_err(&dmard06->client->dev,
"Error reading data: %d\n", ret);
return ret;
}
*val = sign_extend32(ret, DMARD06_SIGN_BIT);
if (dmard06->chip_id == DMARD06_CHIP_ID)
*val = *val >> 1;
switch (chan->type) {
case IIO_ACCEL:
return IIO_VAL_INT;
case IIO_TEMP:
if (dmard06->chip_id != DMARD06_CHIP_ID)
*val = *val / 2;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
switch (chan->type) {
case IIO_TEMP:
*val = DMARD06_TEMP_CENTER_VAL;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ACCEL:
*val = 0;
if (dmard06->chip_id == DMARD06_CHIP_ID)
*val2 = DMARD06_AXIS_SCALE_VAL;
else
*val2 = DMARD05_AXIS_SCALE_VAL;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const struct iio_info dmard06_info = {
.driver_module = THIS_MODULE,
.read_raw = dmard06_read_raw,
};
static int dmard06_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct dmard06_data *dmard06;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C check functionality failed\n");
return -ENXIO;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dmard06));
if (!indio_dev) {
dev_err(&client->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
dmard06 = iio_priv(indio_dev);
dmard06->client = client;
ret = i2c_smbus_read_byte_data(dmard06->client, DMARD06_CHIP_ID_REG);
if (ret < 0) {
dev_err(&client->dev, "Error reading chip id: %d\n", ret);
return ret;
}
if (ret != DMARD05_CHIP_ID && ret != DMARD06_CHIP_ID &&
ret != DMARD07_CHIP_ID) {
dev_err(&client->dev, "Invalid chip id: %02d\n", ret);
return -ENODEV;
}
dmard06->chip_id = ret;
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = DMARD06_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dmard06_channels;
indio_dev->num_channels = ARRAY_SIZE(dmard06_channels);
indio_dev->info = &dmard06_info;
return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
static int dmard06_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct dmard06_data *dmard06 = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
DMARD06_MODE_POWERDOWN);
if (ret < 0)
return ret;
return 0;
}
static int dmard06_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct dmard06_data *dmard06 = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
DMARD06_MODE_NORMAL);
if (ret < 0)
return ret;
return 0;
}
static SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume);
#define DMARD06_PM_OPS (&dmard06_pm_ops)
#else
#define DMARD06_PM_OPS NULL
#endif
static const struct i2c_device_id dmard06_id[] = {
{ "dmard05", 0 },
{ "dmard06", 0 },
{ "dmard07", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard06_id);
static const struct of_device_id dmard06_of_match[] = {
{ .compatible = "domintech,dmard05" },
{ .compatible = "domintech,dmard06" },
{ .compatible = "domintech,dmard07" },
{ }
};
MODULE_DEVICE_TABLE(of, dmard06_of_match);
static struct i2c_driver dmard06_driver = {
.probe = dmard06_probe,
.id_table = dmard06_id,
.driver = {
.name = DMARD06_DRV_NAME,
.of_match_table = of_match_ptr(dmard06_of_match),
.pm = DMARD06_PM_OPS,
},
};
module_i2c_driver(dmard06_driver);
MODULE_AUTHOR("Aleksei Mamlin <mamlinav@gmail.com>");
MODULE_DESCRIPTION("Domintech DMARD06 accelerometer driver");
MODULE_LICENSE("GPL v2");
/*
* IIO driver for the 3-axis accelerometer Domintech DMARD09.
*
* Copyright (c) 2016, Jelle van der Waa <jelle@vdwaa.nl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 <asm/unaligned.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#define DMARD09_DRV_NAME "dmard09"
#define DMARD09_REG_CHIPID 0x18
#define DMARD09_REG_STAT 0x0A
#define DMARD09_REG_X 0x0C
#define DMARD09_REG_Y 0x0E
#define DMARD09_REG_Z 0x10
#define DMARD09_CHIPID 0x95
#define DMARD09_BUF_LEN 8
#define DMARD09_AXIS_X 0
#define DMARD09_AXIS_Y 1
#define DMARD09_AXIS_Z 2
#define DMARD09_AXIS_X_OFFSET ((DMARD09_AXIS_X + 1) * 2)
#define DMARD09_AXIS_Y_OFFSET ((DMARD09_AXIS_Y + 1 )* 2)
#define DMARD09_AXIS_Z_OFFSET ((DMARD09_AXIS_Z + 1) * 2)
struct dmard09_data {
struct i2c_client *client;
};
#define DMARD09_CHANNEL(_axis, offset) { \
.type = IIO_ACCEL, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.modified = 1, \
.address = offset, \
.channel2 = IIO_MOD_##_axis, \
}
static const struct iio_chan_spec dmard09_channels[] = {
DMARD09_CHANNEL(X, DMARD09_AXIS_X_OFFSET),
DMARD09_CHANNEL(Y, DMARD09_AXIS_Y_OFFSET),
DMARD09_CHANNEL(Z, DMARD09_AXIS_Z_OFFSET),
};
static int dmard09_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct dmard09_data *data = iio_priv(indio_dev);
u8 buf[DMARD09_BUF_LEN];
int ret;
s16 accel;
switch (mask) {
case IIO_CHAN_INFO_RAW:
/*
* Read from the DMAR09_REG_STAT register, since the chip
* caches reads from the individual X, Y, Z registers.
*/
ret = i2c_smbus_read_i2c_block_data(data->client,
DMARD09_REG_STAT,
DMARD09_BUF_LEN, buf);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg %d\n",
DMARD09_REG_STAT);
return ret;
}
accel = get_unaligned_le16(&buf[chan->address]);
/* Remove lower 3 bits and sign extend */
accel <<= 4;
accel >>= 7;
*val = accel;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info dmard09_info = {
.driver_module = THIS_MODULE,
.read_raw = dmard09_read_raw,
};
static int dmard09_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct dmard09_data *data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&client->dev, "iio allocation failed\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
data->client = client;
ret = i2c_smbus_read_byte_data(data->client, DMARD09_REG_CHIPID);
if (ret < 0) {
dev_err(&client->dev, "Error reading chip id %d\n", ret);
return ret;
}
if (ret != DMARD09_CHIPID) {
dev_err(&client->dev, "Invalid chip id %d\n", ret);
return -ENODEV;
}
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = DMARD09_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dmard09_channels;
indio_dev->num_channels = ARRAY_SIZE(dmard09_channels);
indio_dev->info = &dmard09_info;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id dmard09_id[] = {
{ "dmard09", 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, dmard09_id);
static struct i2c_driver dmard09_driver = {
.driver = {
.name = DMARD09_DRV_NAME
},
.probe = dmard09_probe,
.id_table = dmard09_id,
};
module_i2c_driver(dmard09_driver);
MODULE_AUTHOR("Jelle van der Waa <jelle@vdwaa.nl>");
MODULE_DESCRIPTION("DMARD09 3-axis accelerometer driver");
MODULE_LICENSE("GPL");
......@@ -1392,6 +1392,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ1013", KXCJK1013},
{"KXCJ1008", KXCJ91008},
{"KXCJ9000", KXCJ91008},
{"KIOX000A", KXCJ91008},
{"KXTJ1009", KXTJ21009},
{"SMO8500", KXCJ91008},
{ },
......
......@@ -317,6 +317,19 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_IOMEM
help
Say yes here to enable support for MediaTek mt65xx AUXADC.
The driver supports immediate mode operation to read from one of sixteen
channels (external or internal).
This driver can also be built as a module. If so, the module will be
called mt6577_auxadc.
config MEN_Z188_ADC
tristate "MEN 16z188 ADC IP Core support"
depends on MCB
......@@ -426,6 +439,18 @@ config TI_ADC128S052
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
config TI_ADC161S626
tristate "Texas Instruments ADC161S626 1-channel differential ADC"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for Texas Instruments ADC141S626,
and ADC161S626 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc161s626.
config TI_ADS1015
tristate "Texas Instruments ADS1015 ADC"
depends on I2C && !SENSORS_ADS1015
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_NAU7802) += nau7802.o
......@@ -41,6 +42,7 @@ obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
......
......@@ -239,16 +239,16 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
ret = -EBUSY;
} else {
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
if (chan->address == AD7298_CH_TEMP)
ret = ad7298_scan_temp(st, val);
else
ret = ad7298_scan_direct(st, chan->address);
}
mutex_unlock(&indio_dev->mlock);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
......
......@@ -519,11 +519,9 @@ static int ad7793_write_raw(struct iio_dev *indio_dev,
int ret, i;
unsigned int tmp;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
......@@ -548,7 +546,7 @@ static int ad7793_write_raw(struct iio_dev *indio_dev,
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
iio_device_release_direct_mode(indio_dev);
return ret;
}
......
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Zhiyong Tao <zhiyong.tao@mediatek.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.
*
* 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/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/iopoll.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
/* Register definitions */
#define MT6577_AUXADC_CON0 0x00
#define MT6577_AUXADC_CON1 0x04
#define MT6577_AUXADC_CON2 0x10
#define MT6577_AUXADC_STA BIT(0)
#define MT6577_AUXADC_DAT0 0x14
#define MT6577_AUXADC_RDY0 BIT(12)
#define MT6577_AUXADC_MISC 0x94
#define MT6577_AUXADC_PDN_EN BIT(14)
#define MT6577_AUXADC_DAT_MASK 0xfff
#define MT6577_AUXADC_SLEEP_US 1000
#define MT6577_AUXADC_TIMEOUT_US 10000
#define MT6577_AUXADC_POWER_READY_MS 1
#define MT6577_AUXADC_SAMPLE_READY_US 25
struct mt6577_auxadc_device {
void __iomem *reg_base;
struct clk *adc_clk;
struct mutex lock;
};
#define MT6577_AUXADC_CHANNEL(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
}
static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
MT6577_AUXADC_CHANNEL(0),
MT6577_AUXADC_CHANNEL(1),
MT6577_AUXADC_CHANNEL(2),
MT6577_AUXADC_CHANNEL(3),
MT6577_AUXADC_CHANNEL(4),
MT6577_AUXADC_CHANNEL(5),
MT6577_AUXADC_CHANNEL(6),
MT6577_AUXADC_CHANNEL(7),
MT6577_AUXADC_CHANNEL(8),
MT6577_AUXADC_CHANNEL(9),
MT6577_AUXADC_CHANNEL(10),
MT6577_AUXADC_CHANNEL(11),
MT6577_AUXADC_CHANNEL(12),
MT6577_AUXADC_CHANNEL(13),
MT6577_AUXADC_CHANNEL(14),
MT6577_AUXADC_CHANNEL(15),
};
static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
u32 or_mask, u32 and_mask)
{
u32 val;
val = readl(reg);
val |= or_mask;
val &= ~and_mask;
writel(val, reg);
}
static int mt6577_auxadc_read(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
u32 val;
void __iomem *reg_channel;
int ret;
struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
chan->channel * 0x04;
mutex_lock(&adc_dev->lock);
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
0, 1 << chan->channel);
/* read channel and make sure old ready bit == 0 */
ret = readl_poll_timeout(reg_channel, val,
((val & MT6577_AUXADC_RDY0) == 0),
MT6577_AUXADC_SLEEP_US,
MT6577_AUXADC_TIMEOUT_US);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"wait for channel[%d] ready bit clear time out\n",
chan->channel);
goto err_timeout;
}
/* set bit to trigger sample */
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
1 << chan->channel, 0);
/* we must delay here for hardware sample channel data */
udelay(MT6577_AUXADC_SAMPLE_READY_US);
/* check MTK_AUXADC_CON2 if auxadc is idle */
ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
((val & MT6577_AUXADC_STA) == 0),
MT6577_AUXADC_SLEEP_US,
MT6577_AUXADC_TIMEOUT_US);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"wait for auxadc idle time out\n");
goto err_timeout;
}
/* read channel and make sure ready bit == 1 */
ret = readl_poll_timeout(reg_channel, val,
((val & MT6577_AUXADC_RDY0) != 0),
MT6577_AUXADC_SLEEP_US,
MT6577_AUXADC_TIMEOUT_US);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"wait for channel[%d] data ready time out\n",
chan->channel);
goto err_timeout;
}
/* read data */
val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
mutex_unlock(&adc_dev->lock);
return val;
err_timeout:
mutex_unlock(&adc_dev->lock);
return -ETIMEDOUT;
}
static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long info)
{
switch (info) {
case IIO_CHAN_INFO_PROCESSED:
*val = mt6577_auxadc_read(indio_dev, chan);
if (*val < 0) {
dev_err(indio_dev->dev.parent,
"failed to sample data on channel[%d]\n",
chan->channel);
return *val;
}
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info mt6577_auxadc_info = {
.driver_module = THIS_MODULE,
.read_raw = &mt6577_auxadc_read_raw,
};
static int mt6577_auxadc_probe(struct platform_device *pdev)
{
struct mt6577_auxadc_device *adc_dev;
unsigned long adc_clk_rate;
struct resource *res;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
if (!indio_dev)
return -ENOMEM;
adc_dev = iio_priv(indio_dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->info = &mt6577_auxadc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mt6577_auxadc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(adc_dev->reg_base)) {
dev_err(&pdev->dev, "failed to get auxadc base address\n");
return PTR_ERR(adc_dev->reg_base);
}
adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
if (IS_ERR(adc_dev->adc_clk)) {
dev_err(&pdev->dev, "failed to get auxadc clock\n");
return PTR_ERR(adc_dev->adc_clk);
}
ret = clk_prepare_enable(adc_dev->adc_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable auxadc clock\n");
return ret;
}
adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
if (!adc_clk_rate) {
ret = -EINVAL;
dev_err(&pdev->dev, "null clock rate\n");
goto err_disable_clk;
}
mutex_init(&adc_dev->lock);
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
MT6577_AUXADC_PDN_EN, 0);
mdelay(MT6577_AUXADC_POWER_READY_MS);
platform_set_drvdata(pdev, indio_dev);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register iio device\n");
goto err_power_off;
}
return 0;
err_power_off:
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0, MT6577_AUXADC_PDN_EN);
err_disable_clk:
clk_disable_unprepare(adc_dev->adc_clk);
return ret;
}
static int mt6577_auxadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0, MT6577_AUXADC_PDN_EN);
clk_disable_unprepare(adc_dev->adc_clk);
return 0;
}
static const struct of_device_id mt6577_auxadc_of_match[] = {
{ .compatible = "mediatek,mt2701-auxadc", },
{ .compatible = "mediatek,mt8173-auxadc", },
{ }
};
MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
static struct platform_driver mt6577_auxadc_driver = {
.driver = {
.name = "mt6577-auxadc",
.of_match_table = mt6577_auxadc_of_match,
},
.probe = mt6577_auxadc_probe,
.remove = mt6577_auxadc_remove,
};
module_platform_driver(mt6577_auxadc_driver);
MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
MODULE_DESCRIPTION("MTK AUXADC Device Driver");
MODULE_LICENSE("GPL v2");
......@@ -197,7 +197,7 @@ static irqreturn_t nau7802_eoc_trigger(int irq, void *private)
if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
st->conversion_count++;
if (st->conversion_count >= NAU7802_MIN_CONVERSIONS)
complete_all(&st->value_ok);
complete(&st->value_ok);
return IRQ_HANDLED;
}
......
/*
* ti-adc161s626.c - Texas Instruments ADC161S626 1-channel differential ADC
*
* ADC Devices Supported:
* adc141s626 - 14-bit ADC
* adc161s626 - 16-bit ADC
*
* Copyright (C) 2016 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/init.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define TI_ADC_DRV_NAME "ti-adc161s626"
enum {
TI_ADC141S626,
TI_ADC161S626,
};
static const struct iio_chan_spec ti_adc141s626_channels[] = {
{
.type = IIO_VOLTAGE,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static const struct iio_chan_spec ti_adc161s626_channels[] = {
{
.type = IIO_VOLTAGE,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
struct ti_adc_data {
struct iio_dev *indio_dev;
struct spi_device *spi;
u8 read_size;
u8 shift;
u8 buffer[16] ____cacheline_aligned;
};
static int ti_adc_read_measurement(struct ti_adc_data *data,
struct iio_chan_spec const *chan, int *val)
{
int ret;
switch (data->read_size) {
case 2: {
__be16 buf;
ret = spi_read(data->spi, (void *) &buf, 2);
if (ret)
return ret;
*val = be16_to_cpu(buf);
break;
}
case 3: {
__be32 buf;
ret = spi_read(data->spi, (void *) &buf, 3);
if (ret)
return ret;
*val = be32_to_cpu(buf) >> 8;
break;
}
default:
return -EINVAL;
}
*val = sign_extend32(*val >> data->shift, chan->scan_type.realbits - 1);
return 0;
}
static irqreturn_t ti_adc_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct ti_adc_data *data = iio_priv(indio_dev);
int ret;
ret = ti_adc_read_measurement(data, &indio_dev->channels[0],
(int *) &data->buffer);
if (!ret)
iio_push_to_buffers_with_timestamp(indio_dev,
data->buffer,
iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ti_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ti_adc_data *data = iio_priv(indio_dev);
int ret;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ti_adc_read_measurement(data, chan, val);
iio_device_release_direct_mode(indio_dev);
if (!ret)
return IIO_VAL_INT;
return 0;
}
static const struct iio_info ti_adc_info = {
.driver_module = THIS_MODULE,
.read_raw = ti_adc_read_raw,
};
static int ti_adc_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ti_adc_data *data;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
indio_dev->info = &ti_adc_info;
indio_dev->dev.parent = &spi->dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = TI_ADC_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
spi_set_drvdata(spi, indio_dev);
data = iio_priv(indio_dev);
data->spi = spi;
switch (spi_get_device_id(spi)->driver_data) {
case TI_ADC141S626:
indio_dev->channels = ti_adc141s626_channels;
indio_dev->num_channels = ARRAY_SIZE(ti_adc141s626_channels);
data->shift = 0;
data->read_size = 2;
break;
case TI_ADC161S626:
indio_dev->channels = ti_adc161s626_channels;
indio_dev->num_channels = ARRAY_SIZE(ti_adc161s626_channels);
data->shift = 6;
data->read_size = 3;
break;
}
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ti_adc_trigger_handler, NULL);
if (ret)
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto error_unreg_buffer;
return 0;
error_unreg_buffer:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int ti_adc_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static const struct of_device_id ti_adc_dt_ids[] = {
{ .compatible = "ti,adc141s626", },
{ .compatible = "ti,adc161s626", },
{}
};
MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
static const struct spi_device_id ti_adc_id[] = {
{"adc141s626", TI_ADC141S626},
{"adc161s626", TI_ADC161S626},
{},
};
MODULE_DEVICE_TABLE(spi, ti_adc_id);
static struct spi_driver ti_adc_driver = {
.driver = {
.name = TI_ADC_DRV_NAME,
.of_match_table = of_match_ptr(ti_adc_dt_ids),
},
.probe = ti_adc_probe,
.remove = ti_adc_remove,
.id_table = ti_adc_id,
};
module_spi_driver(ti_adc_driver);
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
MODULE_DESCRIPTION("Texas Instruments ADC1x1S 1-channel differential ADC");
MODULE_LICENSE("GPL");
......@@ -18,6 +18,7 @@ struct iio_cb_buffer {
int (*cb)(const void *data, void *private);
void *private;
struct iio_channel *channels;
struct iio_dev *indio_dev;
};
static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer)
......@@ -52,7 +53,6 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
{
int ret;
struct iio_cb_buffer *cb_buff;
struct iio_dev *indio_dev;
struct iio_channel *chan;
cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
......@@ -72,17 +72,17 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
goto error_free_cb_buff;
}
indio_dev = cb_buff->channels[0].indio_dev;
cb_buff->indio_dev = cb_buff->channels[0].indio_dev;
cb_buff->buffer.scan_mask
= kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long),
GFP_KERNEL);
= kcalloc(BITS_TO_LONGS(cb_buff->indio_dev->masklength),
sizeof(long), GFP_KERNEL);
if (cb_buff->buffer.scan_mask == NULL) {
ret = -ENOMEM;
goto error_release_channels;
}
chan = &cb_buff->channels[0];
while (chan->indio_dev) {
if (chan->indio_dev != indio_dev) {
if (chan->indio_dev != cb_buff->indio_dev) {
ret = -EINVAL;
goto error_free_scan_mask;
}
......@@ -105,17 +105,14 @@ EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
{
return iio_update_buffers(cb_buff->channels[0].indio_dev,
&cb_buff->buffer,
return iio_update_buffers(cb_buff->indio_dev, &cb_buff->buffer,
NULL);
}
EXPORT_SYMBOL_GPL(iio_channel_start_all_cb);
void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff)
{
iio_update_buffers(cb_buff->channels[0].indio_dev,
NULL,
&cb_buff->buffer);
iio_update_buffers(cb_buff->indio_dev, NULL, &cb_buff->buffer);
}
EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
......@@ -133,6 +130,13 @@ struct iio_channel
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
struct iio_dev
*iio_channel_cb_get_iio_dev(const struct iio_cb_buffer *cb_buffer)
{
return cb_buffer->indio_dev;
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Industrial I/O callback buffer");
MODULE_LICENSE("GPL");
......@@ -16,6 +16,7 @@ config ATLAS_PH_SENSOR
Atlas Scientific OEM SM sensors:
* pH SM sensor
* EC SM sensor
* ORP SM sensor
To compile this driver as module, choose M here: the
module will be called atlas-ph-sensor.
......
......@@ -66,12 +66,17 @@
#define ATLAS_REG_TDS_DATA 0x1c
#define ATLAS_REG_PSS_DATA 0x20
#define ATLAS_REG_ORP_CALIB_STATUS 0x0d
#define ATLAS_REG_ORP_DATA 0x0e
#define ATLAS_PH_INT_TIME_IN_US 450000
#define ATLAS_EC_INT_TIME_IN_US 650000
#define ATLAS_ORP_INT_TIME_IN_US 450000
enum {
ATLAS_PH_SM,
ATLAS_EC_SM,
ATLAS_ORP_SM,
};
struct atlas_data {
......@@ -84,26 +89,10 @@ struct atlas_data {
__be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
};
static const struct regmap_range atlas_volatile_ranges[] = {
regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4),
};
static const struct regmap_access_table atlas_volatile_table = {
.yes_ranges = atlas_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(atlas_volatile_ranges),
};
static const struct regmap_config atlas_regmap_config = {
.name = ATLAS_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &atlas_volatile_table,
.max_register = ATLAS_REG_PSS_DATA + 4,
.cache_type = REGCACHE_RBTREE,
};
static const struct iio_chan_spec atlas_ph_channels[] = {
......@@ -175,6 +164,23 @@ static const struct iio_chan_spec atlas_ec_channels[] = {
},
};
static const struct iio_chan_spec atlas_orp_channels[] = {
{
.type = IIO_VOLTAGE,
.address = ATLAS_REG_ORP_DATA,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int atlas_check_ph_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
......@@ -240,6 +246,22 @@ static int atlas_check_ec_calibration(struct atlas_data *data)
return 0;
}
static int atlas_check_orp_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
int ret;
unsigned int val;
ret = regmap_read(data->regmap, ATLAS_REG_ORP_CALIB_STATUS, &val);
if (ret)
return ret;
if (!val)
dev_warn(dev, "device has not been calibrated\n");
return 0;
};
struct atlas_device {
const struct iio_chan_spec *channels;
int num_channels;
......@@ -264,7 +286,13 @@ static struct atlas_device atlas_devices[] = {
.calibration = &atlas_check_ec_calibration,
.delay = ATLAS_EC_INT_TIME_IN_US,
},
[ATLAS_ORP_SM] = {
.channels = atlas_orp_channels,
.num_channels = 2,
.data_reg = ATLAS_REG_ORP_DATA,
.calibration = &atlas_check_orp_calibration,
.delay = ATLAS_ORP_INT_TIME_IN_US,
},
};
static int atlas_set_powermode(struct atlas_data *data, int on)
......@@ -402,15 +430,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
case IIO_PH:
case IIO_CONCENTRATION:
case IIO_ELECTRICALCONDUCTIVITY:
mutex_lock(&indio_dev->mlock);
case IIO_VOLTAGE:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = atlas_read_measurement(data,
chan->address, &reg);
ret = atlas_read_measurement(data, chan->address, &reg);
mutex_unlock(&indio_dev->mlock);
iio_device_release_direct_mode(indio_dev);
break;
default:
ret = -EINVAL;
......@@ -440,6 +467,10 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
*val = 0; /* 0.000000001 */
*val2 = 1000;
return IIO_VAL_INT_PLUS_NANO;
case IIO_VOLTAGE:
*val = 1; /* 0.1 */
*val2 = 10;
break;
default:
return -EINVAL;
}
......@@ -475,6 +506,7 @@ static const struct iio_info atlas_info = {
static const struct i2c_device_id atlas_id[] = {
{ "atlas-ph-sm", ATLAS_PH_SM},
{ "atlas-ec-sm", ATLAS_EC_SM},
{ "atlas-orp-sm", ATLAS_ORP_SM},
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
......@@ -482,6 +514,7 @@ MODULE_DEVICE_TABLE(i2c, atlas_id);
static const struct of_device_id atlas_dt_ids[] = {
{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
{ .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
......
......@@ -122,6 +122,14 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
#endif
}
static void hid_sensor_set_power_work(struct work_struct *work)
{
struct hid_sensor_common *attrb = container_of(work,
struct hid_sensor_common,
work);
_hid_sensor_power_state(attrb, true);
}
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
......@@ -130,6 +138,7 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
{
cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
}
......@@ -170,6 +179,9 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
goto error_unreg_trigger;
iio_device_set_drvdata(indio_dev, attrb);
INIT_WORK(&attrb->work, hid_sensor_set_power_work);
pm_suspend_ignore_children(&attrb->pdev->dev, true);
pm_runtime_enable(&attrb->pdev->dev);
/* Default to 3 seconds, but can be changed from sysfs */
......@@ -202,7 +214,15 @@ static int hid_sensor_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
schedule_work(&attrb->work);
return 0;
}
static int hid_sensor_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
return _hid_sensor_power_state(attrb, true);
}
......@@ -211,7 +231,7 @@ static int hid_sensor_resume(struct device *dev)
const struct dev_pm_ops hid_sensor_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume)
SET_RUNTIME_PM_OPS(hid_sensor_suspend,
hid_sensor_resume, NULL)
hid_sensor_runtime_resume, NULL)
};
EXPORT_SYMBOL(hid_sensor_pm_ops);
......
......@@ -181,6 +181,15 @@ config AD7303
To compile this driver as module choose M here: the module will be called
ad7303.
config CIO_DAC
tristate "Measurement Computing CIO-DAC IIO driver"
depends on X86 && ISA_BUS_API
help
Say yes here to build support for the Measurement Computing CIO-DAC
analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The
base port addresses for the devices may be configured via the base
array module parameter.
config LPC18XX_DAC
tristate "NXP LPC18xx DAC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
......
......@@ -20,6 +20,7 @@ obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
......
/*
* IIO driver for the Measurement Computing CIO-DAC
* Copyright (C) 2016 William Breathitt Gray
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This 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.
*
* This driver supports the following Measurement Computing devices: CIO-DAC16,
* CIO-DAC06, and PC104-DAC06.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#define CIO_DAC_NUM_CHAN 16
#define CIO_DAC_CHAN(chan) { \
.type = IIO_VOLTAGE, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.indexed = 1, \
.output = 1 \
}
#define CIO_DAC_EXTENT 32
static unsigned int base[max_num_isa_dev(CIO_DAC_EXTENT)];
static unsigned int num_cio_dac;
module_param_array(base, uint, &num_cio_dac, 0);
MODULE_PARM_DESC(base, "Measurement Computing CIO-DAC base addresses");
/**
* struct cio_dac_iio - IIO device private data structure
* @chan_out_states: channels' output states
* @base: base port address of the IIO device
*/
struct cio_dac_iio {
int chan_out_states[CIO_DAC_NUM_CHAN];
unsigned int base;
};
static int cio_dac_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct cio_dac_iio *const priv = iio_priv(indio_dev);
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
*val = priv->chan_out_states[chan->channel];
return IIO_VAL_INT;
}
static int cio_dac_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct cio_dac_iio *const priv = iio_priv(indio_dev);
const unsigned int chan_addr_offset = 2 * chan->channel;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
/* DAC can only accept up to a 16-bit value */
if ((unsigned int)val > 65535)
return -EINVAL;
priv->chan_out_states[chan->channel] = val;
outw(val, priv->base + chan_addr_offset);
return 0;
}
static const struct iio_info cio_dac_info = {
.driver_module = THIS_MODULE,
.read_raw = cio_dac_read_raw,
.write_raw = cio_dac_write_raw
};
static const struct iio_chan_spec cio_dac_channels[CIO_DAC_NUM_CHAN] = {
CIO_DAC_CHAN(0), CIO_DAC_CHAN(1), CIO_DAC_CHAN(2), CIO_DAC_CHAN(3),
CIO_DAC_CHAN(4), CIO_DAC_CHAN(5), CIO_DAC_CHAN(6), CIO_DAC_CHAN(7),
CIO_DAC_CHAN(8), CIO_DAC_CHAN(9), CIO_DAC_CHAN(10), CIO_DAC_CHAN(11),
CIO_DAC_CHAN(12), CIO_DAC_CHAN(13), CIO_DAC_CHAN(14), CIO_DAC_CHAN(15)
};
static int cio_dac_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct cio_dac_iio *priv;
unsigned int i;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
if (!devm_request_region(dev, base[id], CIO_DAC_EXTENT,
dev_name(dev))) {
dev_err(dev, "Unable to request port addresses (0x%X-0x%X)\n",
base[id], base[id] + CIO_DAC_EXTENT);
return -EBUSY;
}
indio_dev->info = &cio_dac_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = cio_dac_channels;
indio_dev->num_channels = CIO_DAC_NUM_CHAN;
indio_dev->name = dev_name(dev);
priv = iio_priv(indio_dev);
priv->base = base[id];
/* initialize DAC outputs to 0V */
for (i = 0; i < 32; i += 2)
outw(0, base[id] + i);
return devm_iio_device_register(dev, indio_dev);
}
static struct isa_driver cio_dac_driver = {
.probe = cio_dac_probe,
.driver = {
.name = "cio-dac"
}
};
module_isa_driver(cio_dac_driver, num_cio_dac);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("Measurement Computing CIO-DAC IIO driver");
MODULE_LICENSE("GPL v2");
......@@ -26,8 +26,8 @@ config HDC100X
tristate "TI HDC100x relative humidity and temperature sensor"
depends on I2C
help
Say yes here to build support for the TI HDC100x series of
relative humidity and temperature sensors.
Say yes here to build support for the Texas Instruments
HDC1000 and HDC1008 relative humidity and temperature sensors.
To compile this driver as a module, choose M here: the module
will be called hdc100x.
......
......@@ -333,11 +333,11 @@ config US5182D
will be called us5182d.
config VCNL4000
tristate "VCNL4000 combined ALS and proximity sensor"
tristate "VCNL4000/4010/4020 combined ALS and proximity sensor"
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VCNL4000
combined ambient light and proximity sensor.
Say Y here if you want to build a driver for the Vishay VCNL4000,
VCNL4010, VCNL4020 combined ambient light and proximity sensor.
To compile this driver as a module, choose M here: the
module will be called vcnl4000.
......
......@@ -894,7 +894,7 @@ static int us5182d_probe(struct i2c_client *client,
goto out_err;
if (data->default_continuous) {
pm_runtime_set_active(&client->dev);
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
goto out_err;
}
......
/*
* vcnl4000.c - Support for Vishay VCNL4000 combined ambient light and
* proximity sensor
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020 combined ambient
* light and proximity sensor
*
* Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
*
......@@ -13,6 +13,8 @@
* TODO:
* allow to adjust IR current
* proximity threshold and event handling
* periodic ALS/proximity measurement (VCNL4010/20)
* interrupts (VCNL4010/20)
*/
#include <linux/module.h>
......@@ -24,6 +26,8 @@
#include <linux/iio/sysfs.h>
#define VCNL4000_DRV_NAME "vcnl4000"
#define VCNL4000_ID 0x01
#define VCNL4010_ID 0x02 /* for VCNL4020, VCNL4010 */
#define VCNL4000_COMMAND 0x80 /* Command register */
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
......@@ -37,13 +41,14 @@
#define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
/* Bit masks for COMMAND register */
#define VCNL4000_AL_RDY 0x40 /* ALS data ready? */
#define VCNL4000_PS_RDY 0x20 /* proximity data ready? */
#define VCNL4000_AL_OD 0x10 /* start on-demand ALS measurement */
#define VCNL4000_PS_OD 0x08 /* start on-demand proximity measurement */
#define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
struct vcnl4000_data {
struct i2c_client *client;
struct mutex lock;
};
static const struct i2c_device_id vcnl4000_id[] = {
......@@ -59,16 +64,18 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
__be16 buf;
int ret;
mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
req_mask);
if (ret < 0)
return ret;
goto fail;
/* wait for data to become ready */
while (tries--) {
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_COMMAND);
if (ret < 0)
return ret;
goto fail;
if (ret & rdy_mask)
break;
msleep(20); /* measurement takes up to 100 ms */
......@@ -77,17 +84,23 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
if (tries < 0) {
dev_err(&data->client->dev,
"vcnl4000_measure() failed, data not ready\n");
return -EIO;
ret = -EIO;
goto fail;
}
ret = i2c_smbus_read_i2c_block_data(data->client,
data_reg, sizeof(buf), (u8 *) &buf);
if (ret < 0)
return ret;
goto fail;
mutex_unlock(&data->lock);
*val = be16_to_cpu(buf);
return 0;
fail:
mutex_unlock(&data->lock);
return ret;
}
static const struct iio_chan_spec vcnl4000_channels[] = {
......@@ -105,7 +118,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret = -EINVAL;
int ret;
struct vcnl4000_data *data = iio_priv(indio_dev);
switch (mask) {
......@@ -117,32 +130,27 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
VCNL4000_AL_RESULT_HI, val);
if (ret < 0)
return ret;
ret = IIO_VAL_INT;
break;
return IIO_VAL_INT;
case IIO_PROXIMITY:
ret = vcnl4000_measure(data,
VCNL4000_PS_OD, VCNL4000_PS_RDY,
VCNL4000_PS_RESULT_HI, val);
if (ret < 0)
return ret;
ret = IIO_VAL_INT;
break;
return IIO_VAL_INT;
default:
break;
return -EINVAL;
}
break;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_LIGHT) {
if (chan->type != IIO_LIGHT)
return -EINVAL;
*val = 0;
*val2 = 250000;
ret = IIO_VAL_INT_PLUS_MICRO;
}
break;
return IIO_VAL_INT_PLUS_MICRO;
default:
break;
return -EINVAL;
}
return ret;
}
static const struct iio_info vcnl4000_info = {
......@@ -155,7 +163,7 @@ static int vcnl4000_probe(struct i2c_client *client,
{
struct vcnl4000_data *data;
struct iio_dev *indio_dev;
int ret;
int ret, prod_id;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
......@@ -164,13 +172,19 @@ static int vcnl4000_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
if (ret < 0)
return ret;
dev_info(&client->dev, "VCNL4000 Ambient light/proximity sensor, Prod %02x, Rev: %02x\n",
ret >> 4, ret & 0xf);
prod_id = ret >> 4;
if (prod_id != VCNL4010_ID && prod_id != VCNL4000_ID)
return -ENODEV;
dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
(prod_id == VCNL4010_ID) ? "VCNL4010/4020" : "VCNL4000",
ret & 0xf);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &vcnl4000_info;
......
......@@ -5,8 +5,22 @@
menu "Magnetometer sensors"
config AK8974
tristate "Asahi Kasei AK8974 3-Axis Magnetometer"
depends on I2C
depends on OF
select REGMAP_I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Asahi Kasei AK8974 or
AMI305 I2C-based 3-axis magnetometer chips.
To compile this driver as a module, choose M here: the module
will be called ak8974.
config AK8975
tristate "Asahi Kasei AK 3-Axis Magnetometer"
tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
depends on I2C
depends on GPIOLIB || COMPILE_TEST
select IIO_BUFFER
......
......@@ -3,6 +3,7 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AK8974) += ak8974.o
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
obj-$(CONFIG_BMC150_MAGN_I2C) += bmc150_magn_i2c.o
......
This diff is collapsed.
......@@ -154,34 +154,41 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
switch (chan->type) {
case IIO_MAGN: /* in 0.1 uT / LSB */
ret = mag3110_read(data, buffer);
if (ret < 0)
return ret;
goto release;
*val = sign_extend32(
be16_to_cpu(buffer[chan->scan_index]), 15);
return IIO_VAL_INT;
ret = IIO_VAL_INT;
break;
case IIO_TEMP: /* in 1 C / LSB */
mutex_lock(&data->lock);
ret = mag3110_request(data);
if (ret < 0) {
mutex_unlock(&data->lock);
return ret;
goto release;
}
ret = i2c_smbus_read_byte_data(data->client,
MAG3110_DIE_TEMP);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
goto release;
*val = sign_extend32(ret, 7);
return IIO_VAL_INT;
ret = IIO_VAL_INT;
break;
default:
return -EINVAL;
ret = -EINVAL;
}
release:
iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_MAGN:
......
......@@ -516,7 +516,7 @@ static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
sx9500_push_events(indio_dev);
if (val & SX9500_CONVDONE_IRQ)
complete_all(&data->completion);
complete(&data->completion);
out:
mutex_unlock(&data->mutex);
......
......@@ -3,6 +3,22 @@
#
menu "Temperature sensors"
config MAXIM_THERMOCOUPLE
tristate "Maxim thermocouple sensors"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for the Maxim series of
thermocouple sensors connected via SPI.
Supported sensors:
* MAX6675
* MAX31855
This driver can also be built as a module. If so, the module will
be called maxim_thermocouple.
config MLX90614
tristate "MLX90614 contact-less infrared sensor"
depends on I2C
......
......@@ -2,6 +2,7 @@
# Makefile for industrial I/O temperature drivers
#
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TSYS01) += tsys01.o
......
/*
* maxim_thermocouple.c - Support for Maxim thermocouple chips
*
* Copyright (C) 2016 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/init.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#define MAXIM_THERMOCOUPLE_DRV_NAME "maxim_thermocouple"
enum {
MAX6675,
MAX31855,
};
const struct iio_chan_spec max6675_channels[] = {
{ /* thermocouple temperature */
.type = IIO_TEMP,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 13,
.storagebits = 16,
.shift = 3,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
const struct iio_chan_spec max31855_channels[] = {
{ /* thermocouple temperature */
.type = IIO_TEMP,
.address = 2,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
.shift = 2,
.endianness = IIO_BE,
},
},
{ /* cold junction temperature */
.type = IIO_TEMP,
.address = 0,
.channel2 = IIO_MOD_TEMP_AMBIENT,
.modified = 1,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 1,
.scan_type = {
.sign = 's',
.realbits = 12,
.storagebits = 16,
.shift = 4,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static const unsigned long max31855_scan_masks[] = {0x3, 0};
struct maxim_thermocouple_chip {
const struct iio_chan_spec *channels;
const unsigned long *scan_masks;
u8 num_channels;
u8 read_size;
/* bit-check for valid input */
u32 status_bit;
};
const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = {
[MAX6675] = {
.channels = max6675_channels,
.num_channels = ARRAY_SIZE(max6675_channels),
.read_size = 2,
.status_bit = BIT(2),
},
[MAX31855] = {
.channels = max31855_channels,
.num_channels = ARRAY_SIZE(max31855_channels),
.read_size = 4,
.scan_masks = max31855_scan_masks,
.status_bit = BIT(16),
},
};
struct maxim_thermocouple_data {
struct spi_device *spi;
const struct maxim_thermocouple_chip *chip;
u8 buffer[16] ____cacheline_aligned;
};
static int maxim_thermocouple_read(struct maxim_thermocouple_data *data,
struct iio_chan_spec const *chan, int *val)
{
unsigned int storage_bytes = data->chip->read_size;
unsigned int shift = chan->scan_type.shift + (chan->address * 8);
unsigned int buf;
int ret;
ret = spi_read(data->spi, (void *) &buf, storage_bytes);
if (ret)
return ret;
switch (storage_bytes) {
case 2:
*val = be16_to_cpu(buf);
break;
case 4:
*val = be32_to_cpu(buf);
break;
}
/* check to be sure this is a valid reading */
if (*val & data->chip->status_bit)
return -EINVAL;
*val = sign_extend32(*val >> shift, chan->scan_type.realbits - 1);
return 0;
}
static irqreturn_t maxim_thermocouple_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct maxim_thermocouple_data *data = iio_priv(indio_dev);
int ret;
ret = spi_read(data->spi, data->buffer, data->chip->read_size);
if (!ret) {
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
iio_get_time_ns(indio_dev));
}
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int maxim_thermocouple_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct maxim_thermocouple_data *data = iio_priv(indio_dev);
int ret = -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = maxim_thermocouple_read(data, chan, val);
iio_device_release_direct_mode(indio_dev);
if (!ret)
return IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->channel2) {
case IIO_MOD_TEMP_AMBIENT:
*val = 62;
*val2 = 500000; /* 1000 * 0.0625 */
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
*val = 250; /* 1000 * 0.25 */
ret = IIO_VAL_INT;
};
break;
}
return ret;
}
static const struct iio_info maxim_thermocouple_info = {
.driver_module = THIS_MODULE,
.read_raw = maxim_thermocouple_read_raw,
};
static int maxim_thermocouple_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct maxim_thermocouple_data *data;
const struct maxim_thermocouple_chip *chip =
&maxim_thermocouple_chips[id->driver_data];
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
indio_dev->info = &maxim_thermocouple_info;
indio_dev->name = MAXIM_THERMOCOUPLE_DRV_NAME;
indio_dev->channels = chip->channels;
indio_dev->available_scan_masks = chip->scan_masks;
indio_dev->num_channels = chip->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
data = iio_priv(indio_dev);
data->spi = spi;
data->chip = chip;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
maxim_thermocouple_trigger_handler, NULL);
if (ret)
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto error_unreg_buffer;
return 0;
error_unreg_buffer:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int maxim_thermocouple_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static const struct spi_device_id maxim_thermocouple_id[] = {
{"max6675", MAX6675},
{"max31855", MAX31855},
{},
};
MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
static struct spi_driver maxim_thermocouple_driver = {
.driver = {
.name = MAXIM_THERMOCOUPLE_DRV_NAME,
},
.probe = maxim_thermocouple_probe,
.remove = maxim_thermocouple_remove,
.id_table = maxim_thermocouple_id,
};
module_spi_driver(maxim_thermocouple_driver);
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
MODULE_DESCRIPTION("Maxim thermocouple sensors");
MODULE_LICENSE("GPL");
This diff is collapsed.
......@@ -27,29 +27,27 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define CONVERSION_TIME_MS 100
#define ISL29028_CONV_TIME_MS 100
#define ISL29028_REG_CONFIGURE 0x01
#define CONFIGURE_ALS_IR_MODE_ALS 0
#define CONFIGURE_ALS_IR_MODE_IR BIT(0)
#define CONFIGURE_ALS_IR_MODE_MASK BIT(0)
#define ISL29028_CONF_ALS_IR_MODE_ALS 0
#define ISL29028_CONF_ALS_IR_MODE_IR BIT(0)
#define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0)
#define CONFIGURE_ALS_RANGE_LOW_LUX 0
#define CONFIGURE_ALS_RANGE_HIGH_LUX BIT(1)
#define CONFIGURE_ALS_RANGE_MASK BIT(1)
#define ISL29028_CONF_ALS_RANGE_LOW_LUX 0
#define ISL29028_CONF_ALS_RANGE_HIGH_LUX BIT(1)
#define ISL29028_CONF_ALS_RANGE_MASK BIT(1)
#define CONFIGURE_ALS_DIS 0
#define CONFIGURE_ALS_EN BIT(2)
#define CONFIGURE_ALS_EN_MASK BIT(2)
#define ISL29028_CONF_ALS_DIS 0
#define ISL29028_CONF_ALS_EN BIT(2)
#define ISL29028_CONF_ALS_EN_MASK BIT(2)
#define CONFIGURE_PROX_DRIVE BIT(3)
#define ISL29028_CONF_PROX_SLP_SH 4
#define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH)
#define CONFIGURE_PROX_SLP_SH 4
#define CONFIGURE_PROX_SLP_MASK (7 << CONFIGURE_PROX_SLP_SH)
#define CONFIGURE_PROX_EN BIT(7)
#define CONFIGURE_PROX_EN_MASK BIT(7)
#define ISL29028_CONF_PROX_EN BIT(7)
#define ISL29028_CONF_PROX_EN_MASK BIT(7)
#define ISL29028_REG_INTERRUPT 0x02
......@@ -62,10 +60,10 @@
#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)
enum als_ir_mode {
MODE_NONE = 0,
MODE_ALS,
MODE_IR
enum isl29028_als_ir_mode {
ISL29028_MODE_NONE = 0,
ISL29028_MODE_ALS,
ISL29028_MODE_IR,
};
struct isl29028_chip {
......@@ -76,7 +74,7 @@ struct isl29028_chip {
bool enable_prox;
int lux_scale;
int als_ir_mode;
enum isl29028_als_ir_mode als_ir_mode;
};
static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
......@@ -91,7 +89,8 @@ static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
break;
}
return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_PROX_SLP_MASK, sel << CONFIGURE_PROX_SLP_SH);
ISL29028_CONF_PROX_SLP_MASK,
sel << ISL29028_CONF_PROX_SLP_SH);
}
static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
......@@ -100,9 +99,9 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
int val = 0;
if (enable)
val = CONFIGURE_PROX_EN;
val = ISL29028_CONF_PROX_EN;
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_PROX_EN_MASK, val);
ISL29028_CONF_PROX_EN_MASK, val);
if (ret < 0)
return ret;
......@@ -113,40 +112,40 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
{
int val = (lux_scale == 2000) ? CONFIGURE_ALS_RANGE_HIGH_LUX :
CONFIGURE_ALS_RANGE_LOW_LUX;
int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX :
ISL29028_CONF_ALS_RANGE_LOW_LUX;
return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_ALS_RANGE_MASK, val);
ISL29028_CONF_ALS_RANGE_MASK, val);
}
static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
enum als_ir_mode mode)
enum isl29028_als_ir_mode mode)
{
int ret = 0;
switch (mode) {
case MODE_ALS:
case ISL29028_MODE_ALS:
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_ALS_IR_MODE_MASK,
CONFIGURE_ALS_IR_MODE_ALS);
ISL29028_CONF_ALS_IR_MODE_MASK,
ISL29028_CONF_ALS_IR_MODE_ALS);
if (ret < 0)
return ret;
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_ALS_RANGE_MASK,
CONFIGURE_ALS_RANGE_HIGH_LUX);
ISL29028_CONF_ALS_RANGE_MASK,
ISL29028_CONF_ALS_RANGE_HIGH_LUX);
break;
case MODE_IR:
case ISL29028_MODE_IR:
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_ALS_IR_MODE_MASK,
CONFIGURE_ALS_IR_MODE_IR);
ISL29028_CONF_ALS_IR_MODE_MASK,
ISL29028_CONF_ALS_IR_MODE_IR);
break;
case MODE_NONE:
case ISL29028_MODE_NONE:
return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_DIS);
ISL29028_CONF_ALS_EN_MASK, ISL29028_CONF_ALS_DIS);
}
if (ret < 0)
......@@ -154,12 +153,13 @@ static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
/* Enable the ALS/IR */
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_EN);
ISL29028_CONF_ALS_EN_MASK,
ISL29028_CONF_ALS_EN);
if (ret < 0)
return ret;
/* Need to wait for conversion time if ALS/IR mode enabled */
mdelay(CONVERSION_TIME_MS);
mdelay(ISL29028_CONV_TIME_MS);
return 0;
}
......@@ -223,14 +223,14 @@ static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
int ret;
int als_ir_data;
if (chip->als_ir_mode != MODE_ALS) {
ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
if (chip->als_ir_mode != ISL29028_MODE_ALS) {
ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS);
if (ret < 0) {
dev_err(dev,
"Error in enabling ALS mode err %d\n", ret);
return ret;
}
chip->als_ir_mode = MODE_ALS;
chip->als_ir_mode = ISL29028_MODE_ALS;
}
ret = isl29028_read_als_ir(chip, &als_ir_data);
......@@ -256,14 +256,14 @@ static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
struct device *dev = regmap_get_device(chip->regmap);
int ret;
if (chip->als_ir_mode != MODE_IR) {
ret = isl29028_set_als_ir_mode(chip, MODE_IR);
if (chip->als_ir_mode != ISL29028_MODE_IR) {
ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR);
if (ret < 0) {
dev_err(dev,
"Error in enabling IR mode err %d\n", ret);
return ret;
}
chip->als_ir_mode = MODE_IR;
chip->als_ir_mode = ISL29028_MODE_IR;
}
return isl29028_read_als_ir(chip, ir_data);
}
......@@ -383,8 +383,8 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
}
static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
"1, 3, 5, 10, 13, 20, 83, 100");
static IIO_CONST_ATTR(in_illuminance_scale_available, "125, 2000");
"1 3 5 10 13 20 83 100");
static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000");
#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
......@@ -428,7 +428,7 @@ static int isl29028_chip_init(struct isl29028_chip *chip)
chip->enable_prox = false;
chip->prox_sampling = 20;
chip->lux_scale = 2000;
chip->als_ir_mode = MODE_NONE;
chip->als_ir_mode = ISL29028_MODE_NONE;
ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
if (ret < 0) {
......@@ -462,7 +462,7 @@ static int isl29028_chip_init(struct isl29028_chip *chip)
return ret;
}
static bool is_volatile_reg(struct device *dev, unsigned int reg)
static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case ISL29028_REG_INTERRUPT:
......@@ -478,7 +478,7 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg)
static const struct regmap_config isl29028_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = is_volatile_reg,
.volatile_reg = isl29028_is_volatile_reg,
.max_register = ISL29028_NUM_REGS - 1,
.num_reg_defaults_raw = ISL29028_NUM_REGS,
.cache_type = REGCACHE_RBTREE,
......@@ -546,7 +546,6 @@ static const struct of_device_id isl29028_of_match[] = {
MODULE_DEVICE_TABLE(of, isl29028_of_match);
static struct i2c_driver isl29028_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "isl29028",
.of_match_table = isl29028_of_match,
......
......@@ -236,6 +236,7 @@ struct hid_sensor_common {
struct hid_sensor_hub_attribute_info report_state;
struct hid_sensor_hub_attribute_info power_state;
struct hid_sensor_hub_attribute_info sensitivity;
struct work_struct work;
};
/* Convert from hid unit expo to regular exponent */
......
......@@ -164,6 +164,18 @@ void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff);
struct iio_channel
*iio_channel_cb_get_channels(const struct iio_cb_buffer *cb_buffer);
/**
* iio_channel_cb_get_iio_dev() - get access to the underlying device.
* @cb_buffer: The callback buffer from whom we want the device
* information.
*
* This function allows one to obtain information about the device.
* The primary aim is to allow drivers that are consuming a device to query
* things like current trigger.
*/
struct iio_dev
*iio_channel_cb_get_iio_dev(const struct iio_cb_buffer *cb_buffer);
/**
* iio_read_channel_raw() - read from a given channel
* @chan: The channel being queried.
......
......@@ -51,7 +51,8 @@ static int dump_channels(const char *dev_dir_name)
while (ent = readdir(dp), ent)
if (check_prefix(ent->d_name, "in_") &&
check_postfix(ent->d_name, "_raw"))
(check_postfix(ent->d_name, "_raw") ||
check_postfix(ent->d_name, "_input")))
printf(" %-10s\n", ent->d_name);
return (closedir(dp) == -1) ? -errno : 0;
......
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