1
0
Fork 0

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.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIuBAABCAAYBQJXvMBjERxqaWMyM0BrZXJuZWwub3JnAAoJEFSFNJnE9BaInZAP
 /0yQg+tm9eBpjaVAdfV2ecuf0hVNdCjFg/7n5MLuSN1aDTPRn3O3nuwp8R8ARoe+
 7ctBFTIOJVqQpLYpunde1iJcOtEk2DIJEnxZQJjExOgn7AwIS4fgqSZQP7u5vDoT
 xrZe8nf5fcvMa1KIvWAadDNflYnn+Ug464Vt8tTdxL6XBIj0xcf8i62aS44XgGwS
 6boHXW0pVg1/QtvJmuajVCdxSouZyikDXWEpJx0UUlLmv2enF+KaJnKVwfbQ7rf/
 UG5ZhdOarbD4miXm8YC+x46v9FeWysatVpMu7Ch5LHrVVvBQCjIubcsZX/qH9cbS
 5VfV00NENHkNEnUL8luVAbLbwxLSq9pFy3LjJOzWmGlBQxT8X6uinA3XbZoqdouf
 5qu+TFUg1RDkL/6GSOsZ4EAGJfY7D9bCbQ0LQUaqPfcdAFZToE8ldLHapU1GtYjt
 Tj0xUxlzQ3fsRH6hTyhy2goAw0s88ruxcUpld8chCd2JWWD2OZJf7TzHGJ2GuuAj
 2yIYXjlVSKlM9yNCrFOyBrKxeg9n5eQI2f9KBiZZpNzxO2dFwaJkAiMF09sleTVv
 7O58g86ywrohp0eT/1sX6qYENJhZROPJGFMbYVHXhWwD1tqGs69zFVGa6ndL1i7w
 MXJ7c+1XjnaAuHEIPRyGZ6/Np27z6Jz0CpxGB4CyHseS
 =d6Kh
 -----END PGP SIGNATURE-----

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.
hifive-unleashed-5.1
Greg Kroah-Hartman 2016-08-23 17:50:16 -04:00
commit d5bd1eba19
49 changed files with 2817 additions and 274 deletions

View File

@ -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

View File

@ -0,0 +1,19 @@
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>;
};
/* ... */
};

View File

@ -0,0 +1,22 @@
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>;
};

View File

@ -0,0 +1,29 @@
* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
===============
The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
in some Mediatek SoCs which among other things measures the temperatures
in the SoC. It can be used directly with register accesses, but it is also
used by thermal controller which reads the temperatures from the AUXADC
directly via its own bus interface. See
Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
for the Thermal Controller which holds a phandle to the AUXADC.
Required properties:
- 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: adc@11001000 {
compatible = "mediatek,mt2701-auxadc";
reg = <0 0x11001000 0 0x1000>;
clocks = <&pericfg CLK_PERI_AUXADC>;
clock-names = "main";
#io-channel-cells = <1>;
};

View File

@ -0,0 +1,16 @@
* 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>;
};

View File

@ -0,0 +1,22 @@
* 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>;
};

View File

@ -0,0 +1,29 @@
* 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>;
};

View File

@ -0,0 +1,21 @@
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>;
};

View File

@ -1,21 +0,0 @@
MediaTek AUXADC
===============
The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
in some Mediatek SoCs which among other things measures the temperatures
in the SoC. It can be used directly with register accesses, but it is also
used by thermal controller which reads the temperatures from the AUXADC
directly via its own bus interface. See
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
Example:
auxadc: auxadc@11001000 {
compatible = "mediatek,mt8173-auxadc";
reg = <0 0x11001000 0 0x1000>;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -0,0 +1,241 @@
/*
* 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");

View File

@ -0,0 +1,157 @@
/*
* 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");

View File

@ -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},
{ },

View File

@ -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

View File

@ -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

View File

@ -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 {
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);
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);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;

View File

@ -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;
}

View File

@ -0,0 +1,291 @@
/*
* 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");

View File

@ -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;
}

View File

@ -0,0 +1,248 @@
/*
* 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");

View File

@ -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");

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,144 @@
/*
* 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");

View File

@ -26,11 +26,11 @@ 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.
To compile this driver as a module, choose M here: the module
will be called hdc100x.
config HTU21
tristate "Measurement Specialties HTU21 humidity & temperature sensor"

View File

@ -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.

View File

@ -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;
}

View File

@ -1,6 +1,6 @@
/*
* 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) {
*val = 0;
*val2 = 250000;
ret = IIO_VAL_INT_PLUS_MICRO;
}
break;
default:
break;
}
if (chan->type != IIO_LIGHT)
return -EINVAL;
return ret;
*val = 0;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
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;

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,863 @@
/*
* Driver for the Asahi Kasei EMD Corporation AK8974
* and Aichi Steel AMI305 magnetometer chips.
* Based on a patch from Samu Onkalo and the AK8975 IIO driver.
*
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (c) 2010 NVIDIA Corporation.
* Copyright (C) 2016 Linaro Ltd.
*
* Author: Samu Onkalo <samu.p.onkalo@nokia.com>
* Author: Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h> /* For irq_get_irq_data() */
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.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>
/*
* 16-bit registers are little-endian. LSB is at the address defined below
* and MSB is at the next higher address.
*/
/* These registers are common for AK8974 and AMI305 */
#define AK8974_SELFTEST 0x0C
#define AK8974_SELFTEST_IDLE 0x55
#define AK8974_SELFTEST_OK 0xAA
#define AK8974_INFO 0x0D
#define AK8974_WHOAMI 0x0F
#define AK8974_WHOAMI_VALUE_AMI305 0x47
#define AK8974_WHOAMI_VALUE_AK8974 0x48
#define AK8974_DATA_X 0x10
#define AK8974_DATA_Y 0x12
#define AK8974_DATA_Z 0x14
#define AK8974_INT_SRC 0x16
#define AK8974_STATUS 0x18
#define AK8974_INT_CLEAR 0x1A
#define AK8974_CTRL1 0x1B
#define AK8974_CTRL2 0x1C
#define AK8974_CTRL3 0x1D
#define AK8974_INT_CTRL 0x1E
#define AK8974_INT_THRES 0x26 /* Absolute any axis value threshold */
#define AK8974_PRESET 0x30
/* AK8974-specific offsets */
#define AK8974_OFFSET_X 0x20
#define AK8974_OFFSET_Y 0x22
#define AK8974_OFFSET_Z 0x24
/* AMI305-specific offsets */
#define AMI305_OFFSET_X 0x6C
#define AMI305_OFFSET_Y 0x72
#define AMI305_OFFSET_Z 0x78
/* Different temperature registers */
#define AK8974_TEMP 0x31
#define AMI305_TEMP 0x60
#define AK8974_INT_X_HIGH BIT(7) /* Axis over +threshold */
#define AK8974_INT_Y_HIGH BIT(6)
#define AK8974_INT_Z_HIGH BIT(5)
#define AK8974_INT_X_LOW BIT(4) /* Axis below -threshold */
#define AK8974_INT_Y_LOW BIT(3)
#define AK8974_INT_Z_LOW BIT(2)
#define AK8974_INT_RANGE BIT(1) /* Range overflow (any axis) */
#define AK8974_STATUS_DRDY BIT(6) /* Data ready */
#define AK8974_STATUS_OVERRUN BIT(5) /* Data overrun */
#define AK8974_STATUS_INT BIT(4) /* Interrupt occurred */
#define AK8974_CTRL1_POWER BIT(7) /* 0 = standby; 1 = active */
#define AK8974_CTRL1_RATE BIT(4) /* 0 = 10 Hz; 1 = 20 Hz */
#define AK8974_CTRL1_FORCE_EN BIT(1) /* 0 = normal; 1 = force */
#define AK8974_CTRL1_MODE2 BIT(0) /* 0 */
#define AK8974_CTRL2_INT_EN BIT(4) /* 1 = enable interrupts */
#define AK8974_CTRL2_DRDY_EN BIT(3) /* 1 = enable data ready signal */
#define AK8974_CTRL2_DRDY_POL BIT(2) /* 1 = data ready active high */
#define AK8974_CTRL2_RESDEF (AK8974_CTRL2_DRDY_POL)
#define AK8974_CTRL3_RESET BIT(7) /* Software reset */
#define AK8974_CTRL3_FORCE BIT(6) /* Start forced measurement */
#define AK8974_CTRL3_SELFTEST BIT(4) /* Set selftest register */
#define AK8974_CTRL3_RESDEF 0x00
#define AK8974_INT_CTRL_XEN BIT(7) /* Enable interrupt for this axis */
#define AK8974_INT_CTRL_YEN BIT(6)
#define AK8974_INT_CTRL_ZEN BIT(5)
#define AK8974_INT_CTRL_XYZEN (BIT(7)|BIT(6)|BIT(5))
#define AK8974_INT_CTRL_POL BIT(3) /* 0 = active low; 1 = active high */
#define AK8974_INT_CTRL_PULSE BIT(1) /* 0 = latched; 1 = pulse (50 usec) */
#define AK8974_INT_CTRL_RESDEF (AK8974_INT_CTRL_XYZEN | AK8974_INT_CTRL_POL)
/* The AMI305 has elaborate FW version and serial number registers */
#define AMI305_VER 0xE8
#define AMI305_SN 0xEA
#define AK8974_MAX_RANGE 2048
#define AK8974_POWERON_DELAY 50
#define AK8974_ACTIVATE_DELAY 1
#define AK8974_SELFTEST_DELAY 1
/*
* Set the autosuspend to two orders of magnitude larger than the poweron
* delay to make sane reasonable power tradeoff savings (5 seconds in
* this case).
*/
#define AK8974_AUTOSUSPEND_DELAY 5000
#define AK8974_MEASTIME 3
#define AK8974_PWR_ON 1
#define AK8974_PWR_OFF 0
/**
* struct ak8974 - state container for the AK8974 driver
* @i2c: parent I2C client
* @orientation: mounting matrix, flipped axis etc
* @map: regmap to access the AK8974 registers over I2C
* @regs: the avdd and dvdd power regulators
* @name: the name of the part
* @variant: the whoami ID value (for selecting code paths)
* @lock: locks the magnetometer for exclusive use during a measurement
* @drdy_irq: uses the DRDY IRQ line
* @drdy_complete: completion for DRDY
* @drdy_active_low: the DRDY IRQ is active low
*/
struct ak8974 {
struct i2c_client *i2c;
struct iio_mount_matrix orientation;
struct regmap *map;
struct regulator_bulk_data regs[2];
const char *name;
u8 variant;
struct mutex lock;
bool drdy_irq;
struct completion drdy_complete;
bool drdy_active_low;
};
static const char ak8974_reg_avdd[] = "avdd";
static const char ak8974_reg_dvdd[] = "dvdd";
static int ak8974_set_power(struct ak8974 *ak8974, bool mode)
{
int ret;
u8 val;
val = mode ? AK8974_CTRL1_POWER : 0;
val |= AK8974_CTRL1_FORCE_EN;
ret = regmap_write(ak8974->map, AK8974_CTRL1, val);
if (ret < 0)
return ret;
if (mode)
msleep(AK8974_ACTIVATE_DELAY);
return 0;
}
static int ak8974_reset(struct ak8974 *ak8974)
{
int ret;
/* Power on to get register access. Sets CTRL1 reg to reset state */
ret = ak8974_set_power(ak8974, AK8974_PWR_ON);
if (ret)
return ret;
ret = regmap_write(ak8974->map, AK8974_CTRL2, AK8974_CTRL2_RESDEF);
if (ret)
return ret;
ret = regmap_write(ak8974->map, AK8974_CTRL3, AK8974_CTRL3_RESDEF);
if (ret)
return ret;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL,
AK8974_INT_CTRL_RESDEF);
if (ret)
return ret;
/* After reset, power off is default state */
return ak8974_set_power(ak8974, AK8974_PWR_OFF);
}
static int ak8974_configure(struct ak8974 *ak8974)
{
int ret;
ret = regmap_write(ak8974->map, AK8974_CTRL2, AK8974_CTRL2_DRDY_EN |
AK8974_CTRL2_INT_EN);
if (ret)
return ret;
ret = regmap_write(ak8974->map, AK8974_CTRL3, 0);
if (ret)
return ret;
ret = regmap_write(ak8974->map, AK8974_INT_CTRL, AK8974_INT_CTRL_POL);
if (ret)
return ret;
return regmap_write(ak8974->map, AK8974_PRESET, 0);
}
static int ak8974_trigmeas(struct ak8974 *ak8974)
{
unsigned int clear;
u8 mask;
u8 val;
int ret;
/* Clear any previous measurement overflow status */
ret = regmap_read(ak8974->map, AK8974_INT_CLEAR, &clear);
if (ret)
return ret;
/* If we have a DRDY IRQ line, use it */
if (ak8974->drdy_irq) {
mask = AK8974_CTRL2_INT_EN |
AK8974_CTRL2_DRDY_EN |
AK8974_CTRL2_DRDY_POL;
val = AK8974_CTRL2_DRDY_EN;
if (!ak8974->drdy_active_low)
val |= AK8974_CTRL2_DRDY_POL;
init_completion(&ak8974->drdy_complete);
ret = regmap_update_bits(ak8974->map, AK8974_CTRL2,
mask, val);
if (ret)
return ret;
}
/* Force a measurement */
return regmap_update_bits(ak8974->map,
AK8974_CTRL3,
AK8974_CTRL3_FORCE,
AK8974_CTRL3_FORCE);
}
static int ak8974_await_drdy(struct ak8974 *ak8974)
{
int timeout = 2;
unsigned int val;
int ret;
if (ak8974->drdy_irq) {
ret = wait_for_completion_timeout(&ak8974->drdy_complete,
1 + msecs_to_jiffies(1000));
if (!ret) {
dev_err(&ak8974->i2c->dev,
"timeout waiting for DRDY IRQ\n");
return -ETIMEDOUT;
}
return 0;
}
/* Default delay-based poll loop */
do {
msleep(AK8974_MEASTIME);
ret = regmap_read(ak8974->map, AK8974_STATUS, &val);
if (ret < 0)
return ret;
if (val & AK8974_STATUS_DRDY)
return 0;
} while (--timeout);
if (!timeout) {
dev_err(&ak8974->i2c->dev,
"timeout waiting for DRDY\n");
return -ETIMEDOUT;
}
return 0;
}
static int ak8974_getresult(struct ak8974 *ak8974, s16 *result)
{
unsigned int src;
int ret;
ret = ak8974_await_drdy(ak8974);
if (ret)
return ret;
ret = regmap_read(ak8974->map, AK8974_INT_SRC, &src);
if (ret < 0)
return ret;
/* Out of range overflow! Strong magnet close? */
if (src & AK8974_INT_RANGE) {
dev_err(&ak8974->i2c->dev,
"range overflow in sensor\n");
return -ERANGE;
}
ret = regmap_bulk_read(ak8974->map, AK8974_DATA_X, result, 6);
if (ret)
return ret;
return ret;
}
static irqreturn_t ak8974_drdy_irq(int irq, void *d)
{
struct ak8974 *ak8974 = d;
if (!ak8974->drdy_irq)
return IRQ_NONE;
/* TODO: timestamp here to get good measurement stamps */
return IRQ_WAKE_THREAD;
}
static irqreturn_t ak8974_drdy_irq_thread(int irq, void *d)
{
struct ak8974 *ak8974 = d;
unsigned int val;
int ret;
/* Check if this was a DRDY from us */
ret = regmap_read(ak8974->map, AK8974_STATUS, &val);
if (ret < 0) {
dev_err(&ak8974->i2c->dev, "error reading DRDY status\n");
return IRQ_HANDLED;
}
if (val & AK8974_STATUS_DRDY) {
/* Yes this was our IRQ */
complete(&ak8974->drdy_complete);
return IRQ_HANDLED;
}
/* We may be on a shared IRQ, let the next client check */
return IRQ_NONE;
}
static int ak8974_selftest(struct ak8974 *ak8974)
{
struct device *dev = &ak8974->i2c->dev;
unsigned int val;
int ret;
ret = regmap_read(ak8974->map, AK8974_SELFTEST, &val);
if (ret)
return ret;
if (val != AK8974_SELFTEST_IDLE) {
dev_err(dev, "selftest not idle before test\n");
return -EIO;
}
/* Trigger self-test */
ret = regmap_update_bits(ak8974->map,
AK8974_CTRL3,
AK8974_CTRL3_SELFTEST,
AK8974_CTRL3_SELFTEST);
if (ret) {
dev_err(dev, "could not write CTRL3\n");
return ret;
}
msleep(AK8974_SELFTEST_DELAY);
ret = regmap_read(ak8974->map, AK8974_SELFTEST, &val);
if (ret)
return ret;
if (val != AK8974_SELFTEST_OK) {
dev_err(dev, "selftest result NOT OK (%02x)\n", val);
return -EIO;
}
ret = regmap_read(ak8974->map, AK8974_SELFTEST, &val);
if (ret)
return ret;
if (val != AK8974_SELFTEST_IDLE) {
dev_err(dev, "selftest not idle after test (%02x)\n", val);
return -EIO;
}
dev_dbg(dev, "passed self-test\n");
return 0;
}
static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val)
{
int ret;
u16 bulk;
ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2);
if (ret)
return ret;
*val = le16_to_cpu(bulk);
return 0;
}
static int ak8974_detect(struct ak8974 *ak8974)
{
unsigned int whoami;
const char *name;
int ret;
unsigned int fw;
u16 sn;
ret = regmap_read(ak8974->map, AK8974_WHOAMI, &whoami);
if (ret)
return ret;
switch (whoami) {
case AK8974_WHOAMI_VALUE_AMI305:
name = "ami305";
ret = regmap_read(ak8974->map, AMI305_VER, &fw);
if (ret)
return ret;
fw &= 0x7f; /* only bits 0 thru 6 valid */
ret = ak8974_get_u16_val(ak8974, AMI305_SN, &sn);
if (ret)
return ret;
dev_info(&ak8974->i2c->dev,
"detected %s, FW ver %02x, S/N: %04x\n",
name, fw, sn);
break;
case AK8974_WHOAMI_VALUE_AK8974:
name = "ak8974";
dev_info(&ak8974->i2c->dev, "detected AK8974\n");
break;
default:
dev_err(&ak8974->i2c->dev, "unsupported device (%02x) ",
whoami);
return -ENODEV;
}
ak8974->name = name;
ak8974->variant = whoami;
return 0;
}
static int ak8974_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
struct ak8974 *ak8974 = iio_priv(indio_dev);
s16 hw_values[3];
int ret = -EINVAL;
pm_runtime_get_sync(&ak8974->i2c->dev);
mutex_lock(&ak8974->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->address > 2) {
dev_err(&ak8974->i2c->dev, "faulty channel address\n");
ret = -EIO;
goto out_unlock;
}
ret = ak8974_trigmeas(ak8974);
if (ret)
goto out_unlock;
ret = ak8974_getresult(ak8974, hw_values);
if (ret)
goto out_unlock;
/*
* We read all axes and discard all but one, for optimized
* reading, use the triggered buffer.
*/
*val = le16_to_cpu(hw_values[chan->address]);
ret = IIO_VAL_INT;
}
out_unlock:
mutex_unlock(&ak8974->lock);
pm_runtime_mark_last_busy(&ak8974->i2c->dev);
pm_runtime_put_autosuspend(&ak8974->i2c->dev);
return ret;
}
static void ak8974_fill_buffer(struct iio_dev *indio_dev)
{
struct ak8974 *ak8974 = iio_priv(indio_dev);
int ret;
s16 hw_values[8]; /* Three axes + 64bit padding */
pm_runtime_get_sync(&ak8974->i2c->dev);
mutex_lock(&ak8974->lock);
ret = ak8974_trigmeas(ak8974);
if (ret) {
dev_err(&ak8974->i2c->dev, "error triggering measure\n");
goto out_unlock;
}
ret = ak8974_getresult(ak8974, hw_values);
if (ret) {
dev_err(&ak8974->i2c->dev, "error getting measures\n");
goto out_unlock;
}
iio_push_to_buffers_with_timestamp(indio_dev, hw_values,
iio_get_time_ns(indio_dev));
out_unlock:
mutex_unlock(&ak8974->lock);
pm_runtime_mark_last_busy(&ak8974->i2c->dev);
pm_runtime_put_autosuspend(&ak8974->i2c->dev);
}
static irqreturn_t ak8974_handle_trigger(int irq, void *p)
{
const struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
ak8974_fill_buffer(indio_dev);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static const struct iio_mount_matrix *
ak8974_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ak8974 *ak8974 = iio_priv(indio_dev);
return &ak8974->orientation;
}
static const struct iio_chan_spec_ext_info ak8974_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, ak8974_get_mount_matrix),
{ },
};
#define AK8974_AXIS_CHANNEL(axis, index) \
{ \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.ext_info = ak8974_ext_info, \
.address = index, \
.scan_index = index, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_LE \
}, \
}
static const struct iio_chan_spec ak8974_channels[] = {
AK8974_AXIS_CHANNEL(X, 0),
AK8974_AXIS_CHANNEL(Y, 1),
AK8974_AXIS_CHANNEL(Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const unsigned long ak8974_scan_masks[] = { 0x7, 0 };
static const struct iio_info ak8974_info = {
.read_raw = &ak8974_read_raw,
.driver_module = THIS_MODULE,
};
static bool ak8974_writeable_reg(struct device *dev, unsigned int reg)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
struct ak8974 *ak8974 = iio_priv(indio_dev);
switch (reg) {
case AK8974_CTRL1:
case AK8974_CTRL2:
case AK8974_CTRL3:
case AK8974_INT_CTRL:
case AK8974_INT_THRES:
case AK8974_INT_THRES + 1:
case AK8974_PRESET:
case AK8974_PRESET + 1:
return true;
case AK8974_OFFSET_X:
case AK8974_OFFSET_X + 1:
case AK8974_OFFSET_Y:
case AK8974_OFFSET_Y + 1:
case AK8974_OFFSET_Z:
case AK8974_OFFSET_Z + 1:
if (ak8974->variant == AK8974_WHOAMI_VALUE_AK8974)
return true;
return false;
case AMI305_OFFSET_X:
case AMI305_OFFSET_X + 1:
case AMI305_OFFSET_Y:
case AMI305_OFFSET_Y + 1:
case AMI305_OFFSET_Z:
case AMI305_OFFSET_Z + 1:
if (ak8974->variant == AK8974_WHOAMI_VALUE_AMI305)
return true;
return false;
default:
return false;
}
}
static const struct regmap_config ak8974_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xff,
.writeable_reg = ak8974_writeable_reg,
};
static int ak8974_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct ak8974 *ak8974;
unsigned long irq_trig;
int irq = i2c->irq;
int ret;
/* Register with IIO */
indio_dev = devm_iio_device_alloc(&i2c->dev, sizeof(*ak8974));
if (indio_dev == NULL)
return -ENOMEM;
ak8974 = iio_priv(indio_dev);
i2c_set_clientdata(i2c, indio_dev);
ak8974->i2c = i2c;
mutex_init(&ak8974->lock);
ret = of_iio_read_mount_matrix(&i2c->dev,
"mount-matrix",
&ak8974->orientation);
if (ret)
return ret;
ak8974->regs[0].supply = ak8974_reg_avdd;
ak8974->regs[1].supply = ak8974_reg_dvdd;
ret = devm_regulator_bulk_get(&i2c->dev,
ARRAY_SIZE(ak8974->regs),
ak8974->regs);
if (ret < 0) {
dev_err(&i2c->dev, "cannot get regulators\n");
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
if (ret < 0) {
dev_err(&i2c->dev, "cannot enable regulators\n");
return ret;
}
/* Take runtime PM online */
pm_runtime_get_noresume(&i2c->dev);
pm_runtime_set_active(&i2c->dev);
pm_runtime_enable(&i2c->dev);
ak8974->map = devm_regmap_init_i2c(i2c, &ak8974_regmap_config);
if (IS_ERR(ak8974->map)) {
dev_err(&i2c->dev, "failed to allocate register map\n");
return PTR_ERR(ak8974->map);
}
ret = ak8974_set_power(ak8974, AK8974_PWR_ON);
if (ret) {
dev_err(&i2c->dev, "could not power on\n");
goto power_off;
}
ret = ak8974_detect(ak8974);
if (ret) {
dev_err(&i2c->dev, "neither AK8974 nor AMI305 found\n");
goto power_off;
}
ret = ak8974_selftest(ak8974);
if (ret)
dev_err(&i2c->dev, "selftest failed (continuing anyway)\n");
ret = ak8974_reset(ak8974);
if (ret) {
dev_err(&i2c->dev, "AK8974 reset failed\n");
goto power_off;
}
pm_runtime_set_autosuspend_delay(&i2c->dev,
AK8974_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&i2c->dev);
pm_runtime_put(&i2c->dev);
indio_dev->dev.parent = &i2c->dev;
indio_dev->channels = ak8974_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8974_channels);
indio_dev->info = &ak8974_info;
indio_dev->available_scan_masks = ak8974_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = ak8974->name;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ak8974_handle_trigger,
NULL);
if (ret) {
dev_err(&i2c->dev, "triggered buffer setup failed\n");
goto disable_pm;
}
/* If we have a valid DRDY IRQ, make use of it */
if (irq > 0) {
irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
if (irq_trig == IRQF_TRIGGER_RISING) {
dev_info(&i2c->dev, "enable rising edge DRDY IRQ\n");
} else if (irq_trig == IRQF_TRIGGER_FALLING) {
ak8974->drdy_active_low = true;
dev_info(&i2c->dev, "enable falling edge DRDY IRQ\n");
} else {
irq_trig = IRQF_TRIGGER_RISING;
}
irq_trig |= IRQF_ONESHOT;
irq_trig |= IRQF_SHARED;
ret = devm_request_threaded_irq(&i2c->dev,
irq,
ak8974_drdy_irq,
ak8974_drdy_irq_thread,
irq_trig,
ak8974->name,
ak8974);
if (ret) {
dev_err(&i2c->dev, "unable to request DRDY IRQ "
"- proceeding without IRQ\n");
goto no_irq;
}
ak8974->drdy_irq = true;
}
no_irq:
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&i2c->dev, "device register failed\n");
goto cleanup_buffer;
}
return 0;
cleanup_buffer:
iio_triggered_buffer_cleanup(indio_dev);
disable_pm:
pm_runtime_put_noidle(&i2c->dev);
pm_runtime_disable(&i2c->dev);
ak8974_set_power(ak8974, AK8974_PWR_OFF);
power_off:
regulator_bulk_disable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
return ret;
}
static int __exit ak8974_remove(struct i2c_client *i2c)
{
struct iio_dev *indio_dev = i2c_get_clientdata(i2c);
struct ak8974 *ak8974 = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
pm_runtime_get_sync(&i2c->dev);
pm_runtime_put_noidle(&i2c->dev);
pm_runtime_disable(&i2c->dev);
ak8974_set_power(ak8974, AK8974_PWR_OFF);
regulator_bulk_disable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
return 0;
}
#ifdef CONFIG_PM
static int ak8974_runtime_suspend(struct device *dev)
{
struct ak8974 *ak8974 =
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
ak8974_set_power(ak8974, AK8974_PWR_OFF);
regulator_bulk_disable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
return 0;
}
static int ak8974_runtime_resume(struct device *dev)
{
struct ak8974 *ak8974 =
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
if (ret)
return ret;
msleep(AK8974_POWERON_DELAY);
ret = ak8974_set_power(ak8974, AK8974_PWR_ON);
if (ret)
goto out_regulator_disable;
ret = ak8974_configure(ak8974);
if (ret)
goto out_disable_power;
return 0;
out_disable_power:
ak8974_set_power(ak8974, AK8974_PWR_OFF);
out_regulator_disable:
regulator_bulk_disable(ARRAY_SIZE(ak8974->regs), ak8974->regs);
return ret;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops ak8974_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(ak8974_runtime_suspend,
ak8974_runtime_resume, NULL)
};
static const struct i2c_device_id ak8974_id[] = {
{"ami305", 0 },
{"ak8974", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ak8974_id);
static const struct of_device_id ak8974_of_match[] = {
{ .compatible = "asahi-kasei,ak8974", },
{}
};
MODULE_DEVICE_TABLE(of, ak8974_of_match);
static struct i2c_driver ak8974_driver = {
.driver = {
.name = "ak8974",
.owner = THIS_MODULE,
.pm = &ak8974_dev_pm_ops,
.of_match_table = of_match_ptr(ak8974_of_match),
},
.probe = ak8974_probe,
.remove = __exit_p(ak8974_remove),
.id_table = ak8974_id,
};
module_i2c_driver(ak8974_driver);
MODULE_DESCRIPTION("AK8974 and AMI305 3-axis magnetometer driver");
MODULE_AUTHOR("Samu Onkalo");
MODULE_AUTHOR("Linus Walleij");
MODULE_LICENSE("GPL v2");

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,281 @@
/*
* 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");

View File

@ -32,25 +32,25 @@
#include <linux/iio/sysfs.h>
#include <linux/acpi.h>
#define CONVERSION_TIME_MS 100
#define ISL29018_CONV_TIME_MS 100
#define ISL29018_REG_ADD_COMMAND1 0x00
#define COMMMAND1_OPMODE_SHIFT 5
#define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT)
#define COMMMAND1_OPMODE_POWER_DOWN 0
#define COMMMAND1_OPMODE_ALS_ONCE 1
#define COMMMAND1_OPMODE_IR_ONCE 2
#define COMMMAND1_OPMODE_PROX_ONCE 3
#define ISL29018_CMD1_OPMODE_SHIFT 5
#define ISL29018_CMD1_OPMODE_MASK (7 << ISL29018_CMD1_OPMODE_SHIFT)
#define ISL29018_CMD1_OPMODE_POWER_DOWN 0
#define ISL29018_CMD1_OPMODE_ALS_ONCE 1
#define ISL29018_CMD1_OPMODE_IR_ONCE 2
#define ISL29018_CMD1_OPMODE_PROX_ONCE 3
#define ISL29018_REG_ADD_COMMANDII 0x01
#define COMMANDII_RESOLUTION_SHIFT 2
#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT)
#define ISL29018_REG_ADD_COMMAND2 0x01
#define ISL29018_CMD2_RESOLUTION_SHIFT 2
#define ISL29018_CMD2_RESOLUTION_MASK (0x3 << ISL29018_CMD2_RESOLUTION_SHIFT)
#define COMMANDII_RANGE_SHIFT 0
#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT)
#define ISL29018_CMD2_RANGE_SHIFT 0
#define ISL29018_CMD2_RANGE_MASK (0x3 << ISL29018_CMD2_RANGE_SHIFT)
#define COMMANDII_SCHEME_SHIFT 7
#define COMMANDII_SCHEME_MASK (0x1 << COMMANDII_SCHEME_SHIFT)
#define ISL29018_CMD2_SCHEME_SHIFT 7
#define ISL29018_CMD2_SCHEME_MASK (0x1 << ISL29018_CMD2_SCHEME_SHIFT)
#define ISL29018_REG_ADD_DATA_LSB 0x02
#define ISL29018_REG_ADD_DATA_MSB 0x03
@ -127,13 +127,13 @@ static int isl29018_set_integration_time(struct isl29018_chip *chip,
if (i >= ARRAY_SIZE(isl29018_int_utimes[chip->type]))
return -EINVAL;
ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
COMMANDII_RESOLUTION_MASK,
i << COMMANDII_RESOLUTION_SHIFT);
ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
ISL29018_CMD2_RESOLUTION_MASK,
i << ISL29018_CMD2_RESOLUTION_SHIFT);
if (ret < 0)
return ret;
/* keep the same range when integration time changes */
/* Keep the same range when integration time changes */
int_time = chip->int_time;
for (i = 0; i < ARRAY_SIZE(isl29018_scales[int_time]); ++i) {
if (chip->scale.scale == isl29018_scales[int_time][i].scale &&
@ -163,9 +163,9 @@ static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale)
if (i >= ARRAY_SIZE(isl29018_scales[chip->int_time]))
return -EINVAL;
ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
COMMANDII_RANGE_MASK,
i << COMMANDII_RANGE_SHIFT);
ret = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
ISL29018_CMD2_RANGE_MASK,
i << ISL29018_CMD2_RANGE_SHIFT);
if (ret < 0)
return ret;
@ -183,13 +183,13 @@ static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
/* Set mode */
status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
mode << COMMMAND1_OPMODE_SHIFT);
mode << ISL29018_CMD1_OPMODE_SHIFT);
if (status) {
dev_err(dev,
"Error in setting operating mode err %d\n", status);
return status;
}
msleep(CONVERSION_TIME_MS);
msleep(ISL29018_CONV_TIME_MS);
status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb);
if (status < 0) {
dev_err(dev,
@ -213,8 +213,8 @@ static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
int lux_data;
unsigned int data_x_range;
lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
lux_data = isl29018_read_sensor_input(chip,
ISL29018_CMD1_OPMODE_ALS_ONCE);
if (lux_data < 0)
return lux_data;
@ -230,8 +230,8 @@ static int isl29018_read_ir(struct isl29018_chip *chip, int *ir)
{
int ir_data;
ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
ir_data = isl29018_read_sensor_input(chip,
ISL29018_CMD1_OPMODE_IR_ONCE);
if (ir_data < 0)
return ir_data;
@ -249,16 +249,16 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
struct device *dev = regmap_get_device(chip->regmap);
/* Do proximity sensing with required scheme */
status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
COMMANDII_SCHEME_MASK,
scheme << COMMANDII_SCHEME_SHIFT);
status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMAND2,
ISL29018_CMD2_SCHEME_MASK,
scheme << ISL29018_CMD2_SCHEME_SHIFT);
if (status) {
dev_err(dev, "Error in setting operating mode\n");
return status;
}
prox_data = isl29018_read_sensor_input(chip,
COMMMAND1_OPMODE_PROX_ONCE);
ISL29018_CMD1_OPMODE_PROX_ONCE);
if (prox_data < 0)
return prox_data;
@ -267,8 +267,8 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
return 0;
}
ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
ir_data = isl29018_read_sensor_input(chip,
ISL29018_CMD1_OPMODE_IR_ONCE);
if (ir_data < 0)
return ir_data;
@ -280,7 +280,7 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
return 0;
}
static ssize_t show_scale_available(struct device *dev,
static ssize_t isl29018_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@ -297,7 +297,7 @@ static ssize_t show_scale_available(struct device *dev,
return len;
}
static ssize_t show_int_time_available(struct device *dev,
static ssize_t isl29018_show_int_time_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@ -313,8 +313,7 @@ static ssize_t show_int_time_available(struct device *dev,
return len;
}
/* proximity scheme */
static ssize_t show_prox_infrared_suppression(struct device *dev,
static ssize_t isl29018_show_prox_infrared_suppression(struct device *dev,
struct device_attribute *attr,
char *buf)
{
@ -322,13 +321,13 @@ static ssize_t show_prox_infrared_suppression(struct device *dev,
struct isl29018_chip *chip = iio_priv(indio_dev);
/*
* return the "proximity scheme" i.e. if the chip does on chip
* Return the "proximity scheme" i.e. if the chip does on chip
* infrared suppression (1 means perform on chip suppression)
*/
return sprintf(buf, "%d\n", chip->prox_scheme);
}
static ssize_t store_prox_infrared_suppression(struct device *dev,
static ssize_t isl29018_store_prox_infrared_suppression(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@ -338,13 +337,11 @@ static ssize_t store_prox_infrared_suppression(struct device *dev,
if (kstrtoint(buf, 10, &val))
return -EINVAL;
if (!(val == 0 || val == 1)) {
dev_err(dev, "The mode is not supported\n");
if (!(val == 0 || val == 1))
return -EINVAL;
}
/*
* get the "proximity scheme" i.e. if the chip does on chip
* Get the "proximity scheme" i.e. if the chip does on chip
* infrared suppression (1 means perform on chip suppression)
*/
mutex_lock(&chip->lock);
@ -354,7 +351,6 @@ static ssize_t store_prox_infrared_suppression(struct device *dev,
return count;
}
/* Channel IO */
static int isl29018_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
@ -491,13 +487,13 @@ static const struct iio_chan_spec isl29023_channels[] = {
};
static IIO_DEVICE_ATTR(in_illuminance_integration_time_available, S_IRUGO,
show_int_time_available, NULL, 0);
isl29018_show_int_time_available, NULL, 0);
static IIO_DEVICE_ATTR(in_illuminance_scale_available, S_IRUGO,
show_scale_available, NULL, 0);
isl29018_show_scale_available, NULL, 0);
static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_suppression,
S_IRUGO | S_IWUSR,
show_prox_infrared_suppression,
store_prox_infrared_suppression, 0);
isl29018_show_prox_infrared_suppression,
isl29018_store_prox_infrared_suppression, 0);
#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
@ -541,7 +537,7 @@ static int isl29035_detect(struct isl29018_chip *chip)
if (id != ISL29035_DEVICE_ID)
return -ENODEV;
/* clear out brownout bit */
/* Clear brownout bit */
return regmap_update_bits(chip->regmap, ISL29035_REG_DEVICE_ID,
ISL29035_BOUT_MASK, 0);
}
@ -574,7 +570,7 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
* conversions, clear the test registers, and then rewrite all
* registers to the desired values.
* ...
* FOR ISL29011, ISL29018, ISL29021, ISL29023
* For ISL29011, ISL29018, ISL29021, ISL29023
* 1. Write 0x00 to register 0x08 (TEST)
* 2. Write 0x00 to register 0x00 (CMD1)
* 3. Rewrite all registers to the desired values
@ -603,7 +599,7 @@ static int isl29018_chip_init(struct isl29018_chip *chip)
usleep_range(1000, 2000); /* per data sheet, page 10 */
/* set defaults */
/* Set defaults */
status = isl29018_set_scale(chip, chip->scale.scale,
chip->scale.uscale);
if (status < 0) {
@ -635,7 +631,7 @@ static const struct iio_info isl29023_info = {
.write_raw = isl29018_write_raw,
};
static bool is_volatile_reg(struct device *dev, unsigned int reg)
static bool isl29018_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case ISL29018_REG_ADD_DATA_LSB:
@ -649,37 +645,32 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg)
}
}
/*
* isl29018_regmap_config: regmap configuration.
* Use RBTREE mechanism for caching.
*/
static const struct regmap_config isl29018_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = is_volatile_reg,
.volatile_reg = isl29018_is_volatile_reg,
.max_register = ISL29018_REG_TEST,
.num_reg_defaults_raw = ISL29018_REG_TEST + 1,
.cache_type = REGCACHE_RBTREE,
};
/* isl29035_regmap_config: regmap configuration for ISL29035 */
static const struct regmap_config isl29035_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.volatile_reg = is_volatile_reg,
.volatile_reg = isl29018_is_volatile_reg,
.max_register = ISL29035_REG_DEVICE_ID,
.num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1,
.cache_type = REGCACHE_RBTREE,
};
struct chip_info {
struct isl29018_chip_info {
const struct iio_chan_spec *channels;
int num_channels;
const struct iio_info *indio_info;
const struct regmap_config *regmap_cfg;
};
static const struct chip_info chip_info_tbl[] = {
static const struct isl29018_chip_info isl29018_chip_info_tbl[] = {
[isl29018] = {
.channels = isl29018_channels,
.num_channels = ARRAY_SIZE(isl29018_channels),
@ -724,10 +715,8 @@ static int isl29018_probe(struct i2c_client *client,
int dev_id = 0;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev) {
dev_err(&client->dev, "iio allocation fails\n");
if (!indio_dev)
return -ENOMEM;
}
chip = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
@ -750,7 +739,7 @@ static int isl29018_probe(struct i2c_client *client,
chip->suspended = false;
chip->regmap = devm_regmap_init_i2c(client,
chip_info_tbl[dev_id].regmap_cfg);
isl29018_chip_info_tbl[dev_id].regmap_cfg);
if (IS_ERR(chip->regmap)) {
err = PTR_ERR(chip->regmap);
dev_err(&client->dev, "regmap initialization fails: %d\n", err);
@ -761,19 +750,13 @@ static int isl29018_probe(struct i2c_client *client,
if (err)
return err;
indio_dev->info = chip_info_tbl[dev_id].indio_info;
indio_dev->channels = chip_info_tbl[dev_id].channels;
indio_dev->num_channels = chip_info_tbl[dev_id].num_channels;
indio_dev->info = isl29018_chip_info_tbl[dev_id].indio_info;
indio_dev->channels = isl29018_chip_info_tbl[dev_id].channels;
indio_dev->num_channels = isl29018_chip_info_tbl[dev_id].num_channels;
indio_dev->name = name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
err = devm_iio_device_register(&client->dev, indio_dev);
if (err) {
dev_err(&client->dev, "iio registration fails\n");
return err;
}
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
@ -840,7 +823,6 @@ static const struct of_device_id isl29018_of_match[] = {
MODULE_DEVICE_TABLE(of, isl29018_of_match);
static struct i2c_driver isl29018_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "isl29018",
.acpi_match_table = ACPI_PTR(isl29018_acpi_match),

View File

@ -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,

View File

@ -23,8 +23,8 @@
#include "ade7854.h"
static ssize_t ade7854_read_8bit(struct device *dev,
struct device_attribute *attr,
char *buf)
struct device_attribute *attr,
char *buf)
{
int ret;
u8 val = 0;
@ -40,8 +40,8 @@ static ssize_t ade7854_read_8bit(struct device *dev,
}
static ssize_t ade7854_read_16bit(struct device *dev,
struct device_attribute *attr,
char *buf)
struct device_attribute *attr,
char *buf)
{
int ret;
u16 val = 0;
@ -57,8 +57,8 @@ static ssize_t ade7854_read_16bit(struct device *dev,
}
static ssize_t ade7854_read_24bit(struct device *dev,
struct device_attribute *attr,
char *buf)
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val;
@ -74,8 +74,8 @@ static ssize_t ade7854_read_24bit(struct device *dev,
}
static ssize_t ade7854_read_32bit(struct device *dev,
struct device_attribute *attr,
char *buf)
struct device_attribute *attr,
char *buf)
{
int ret;
u32 val = 0;
@ -91,9 +91,9 @@ static ssize_t ade7854_read_32bit(struct device *dev,
}
static ssize_t ade7854_write_8bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@ -112,9 +112,9 @@ error_ret:
}
static ssize_t ade7854_write_16bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@ -133,9 +133,9 @@ error_ret:
}
static ssize_t ade7854_write_24bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@ -154,9 +154,9 @@ error_ret:
}
static ssize_t ade7854_write_32bit(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_to_iio_dev(dev);

View File

@ -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 */

View File

@ -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.

View File

@ -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;