Commit 08cad739 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.11b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into work-next

Jonathan writes:

Second round of IIO new device support, cleanups and features for the 4.11 cycle

New device support:
* lsm6dsx imu
  - new driver and bindings.
* max11100 adc
  - new driver and bindings.
* tlc4541
  - new driver
* tmp007 thermopile
  - new driver.

Core
* in kernel interfaces
  - pass through raw values if no scaling provided and a processed value is
    requested.
* trigger
  - close a race condition in acquiring trigger reference.
  - constify device_type structures.
  - rework the viio_trigger_alloc function to be much neater and easier to
  read.
  - free trigger resources correctly on some error paths. Avoids putting a
  module we don't have.

Documentation
* ABI
  - specify a unit for proximity measurements.

Cleanups and features
* ads1015
  - constify iio_info structure.
* ads7950 cleanups following merge in previous pull
  - Add device tree bindings
  - Drop the ti prefix from the module name in common with other drivers.
  - Change regulator name to vref to match datasheet and other drivers.
* ak8974
  - remove a redundant zero timeout check.
* bmi160
  - use variable names for sizeof instead of types.
* cm3605
  - mark PM functions as __maybe_unused to avoid a build warning.
* isl29028 (on it's way towards moving out of staging).
  - alignment fixes and newline improvements.
  - combine proxim_get and read_proxim for simpler code.
  - drop unused ISL29028_DEV_ATTR macro
  - move some error logging into functions to cut out repitition.
  - make error messages more consistent.
  - tidy up some brackets.
  - drop the enable flag that nothing uses.
  - only set proximity rate and ALS scale when relevant channel type is enabled.
  - runtime pm support.
* lsm6dsx
  - fix wrong values for gyro sensitivitiy.
* mag3110
  - claim direct mode during sysfs reads to avoid a race condition.
* max1363
  - export OF device table IDs as module aliases.
* max30100
  - use msleep for long uncritical delays.
* mcp4531
  - export OF device table as module aliases.
* ms5611
  - claim direct mode during sysfs reads to avoid a race condition.
* opt3001
  - export OF device table as module aliases.
* sx9500
  - claim direct mode during oversampling changes to avoid a race condition.
parents 994261dc 10e840df
......@@ -1255,7 +1255,8 @@ Description:
reflectivity of infrared or ultrasound emitted.
Often these sensors are unit less and as such conversion
to SI units is not possible. Higher proximity measurements
indicate closer objects, and vice versa.
indicate closer objects, and vice versa. Units after
application of scale and offset are meters.
What: /sys/.../iio:deviceX/in_illuminance_input
What: /sys/.../iio:deviceX/in_illuminance_raw
......
* Maxim max11100 Analog to Digital Converter (ADC)
Required properties:
- compatible: Should be "maxim,max11100"
- reg: the adc unit address
- vref-supply: phandle to the regulator that provides reference voltage
Optional properties:
- spi-max-frequency: SPI maximum frequency
Example:
max11100: adc@0 {
compatible = "maxim,max11100";
reg = <0>;
vref-supply = <&adc0_vref>;
spi-max-frequency = <240000>;
};
* Texas Instruments ADS7950 family of A/DC chips
Required properties:
- compatible: Must be one of "ti,ads7950", "ti,ads7951", "ti,ads7952",
"ti,ads7953", "ti,ads7954", "ti,ads7955", "ti,ads7956", "ti,ads7957",
"ti,ads7958", "ti,ads7959", "ti,ads7960", or "ti,ads7961"
- reg: SPI chip select number for the device
- #io-channel-cells: Must be 1 as per ../iio-bindings.txt
- vref-supply: phandle to a regulator node that supplies the 2.5V or 5V
reference voltage
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,ads7957";
reg = <0>;
#io-channel-cells = <1>;
vref-supply = <&refin_supply>;
spi-max-frequency = <10000000>;
};
* ST_LSM6DSx driver for STM 6-axis (acc + gyro) imu Mems sensors
Required properties:
- compatible: must be one of:
"st,lsm6ds3"
"st,lsm6dsm"
- reg: i2c address of the sensor / spi cs line
Optional properties:
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for IRQ. It should be configured with
flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
Refer to interrupt-controller/interrupts.txt for generic interrupt
client node bindings.
Example:
lsm6dsm@6b {
compatible = "st,lsm6dsm";
reg = <0x6b>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
* TI TMP007 - IR thermopile sensor with integrated math engine
Link to datasheet: http://www.ti.com/lit/ds/symlink/tmp007.pdf
Required properties:
- compatible: should be "ti,tmp007"
- reg: the I2C address of the sensor (changeable via ADR pins)
------------------------------
|ADR1 | ADR0 | Device Address|
------------------------------
0 0 0x40
0 1 0x41
0 SDA 0x42
0 SCL 0x43
1 0 0x44
1 1 0x45
1 SDA 0x46
1 SCL 0x47
Example:
tmp007@40 {
compatible = "ti,tmp007";
reg = <0x40>;
};
......@@ -326,6 +326,15 @@ config MAX1027
To compile this driver as a module, choose M here: the module will be
called max1027.
config MAX11100
tristate "Maxim max11100 ADC driver"
depends on SPI_MASTER
help
Say yes here to build support for Maxim max11100 SPI ADC
To compile this driver as a module, choose M here: the module will be
called max11100.
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
......@@ -603,6 +612,18 @@ config TI_AM335X_ADC
To compile this driver as a module, choose M here: the module will be
called ti_am335x_adc.
config TI_TLC4541
tristate "Texas Instruments TLC4541 ADC driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Texas Instruments TLC4541 / TLC3541
ADC chips.
This driver can also be built as a module. If so, the module will be
called ti-tlc4541.
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
......
......@@ -32,6 +32,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
......@@ -55,6 +56,7 @@ obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
......
/*
* iio/adc/max11100.c
* Maxim max11100 ADC Driver with IIO interface
*
* Copyright (C) 2016-17 Renesas Electronics Corporation
* Copyright (C) 2016-17 Jacopo Mondi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
/*
* LSB is the ADC single digital step
* 1 LSB = (vref_mv / 2 ^ 16)
*
* LSB is used to calculate analog voltage value
* from the number of ADC steps count
*
* Ain = (count * LSB)
*/
#define MAX11100_LSB_DIV (1 << 16)
struct max11100_state {
struct regulator *vref_reg;
struct spi_device *spi;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
u8 buffer[3] ____cacheline_aligned;
};
static struct iio_chan_spec max11100_channels[] = {
{ /* [0] */
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static int max11100_read_single(struct iio_dev *indio_dev, int *val)
{
int ret;
struct max11100_state *state = iio_priv(indio_dev);
ret = spi_read(state->spi, state->buffer, sizeof(state->buffer));
if (ret) {
dev_err(&indio_dev->dev, "SPI transfer failed\n");
return ret;
}
/* the first 8 bits sent out from ADC must be 0s */
if (state->buffer[0]) {
dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
return -EINVAL;
}
*val = (state->buffer[1] << 8) | state->buffer[2];
return 0;
}
static int max11100_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
int ret, vref_uv;
struct max11100_state *state = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_RAW:
ret = max11100_read_single(indio_dev, val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
vref_uv = regulator_get_voltage(state->vref_reg);
if (vref_uv < 0)
/* dummy regulator "get_voltage" returns -EINVAL */
return -EINVAL;
*val = vref_uv / 1000;
*val2 = MAX11100_LSB_DIV;
return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
}
static const struct iio_info max11100_info = {
.driver_module = THIS_MODULE,
.read_raw = max11100_read_raw,
};
static int max11100_probe(struct spi_device *spi)
{
int ret;
struct iio_dev *indio_dev;
struct max11100_state *state;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
if (!indio_dev)
return -ENOMEM;
spi_set_drvdata(spi, indio_dev);
state = iio_priv(indio_dev);
state->spi = spi;
indio_dev->dev.parent = &spi->dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = "max11100";
indio_dev->info = &max11100_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = max11100_channels,
indio_dev->num_channels = ARRAY_SIZE(max11100_channels),
state->vref_reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(state->vref_reg))
return PTR_ERR(state->vref_reg);
ret = regulator_enable(state->vref_reg);
if (ret)
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto disable_regulator;
return 0;
disable_regulator:
regulator_disable(state->vref_reg);
return ret;
}
static int max11100_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct max11100_state *state = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(state->vref_reg);
return 0;
}
static const struct of_device_id max11100_ids[] = {
{.compatible = "maxim,max11100"},
{ },
};
MODULE_DEVICE_TABLE(of, max11100_ids);
static struct spi_driver max11100_driver = {
.driver = {
.name = "max11100",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(max11100_ids),
},
.probe = max11100_probe,
.remove = max11100_remove,
};
module_spi_driver(max11100_driver);
MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
MODULE_LICENSE("GPL v2");
......@@ -1567,6 +1567,7 @@ static const struct of_device_id max1363_of_match[] = {
MAX1363_COMPATIBLE("maxim,max11647", max11647),
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, max1363_of_match);
#endif
static int max1363_probe(struct i2c_client *client,
......
......@@ -472,14 +472,14 @@ static const struct attribute_group ads1115_attribute_group = {
.attrs = ads1115_attributes,
};
static struct iio_info ads1015_info = {
static const struct iio_info ads1015_info = {
.driver_module = THIS_MODULE,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
.attrs = &ads1015_attribute_group,
};
static struct iio_info ads1115_info = {
static const struct iio_info ads1115_info = {
.driver_module = THIS_MODULE,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
......
......@@ -411,15 +411,15 @@ static int ti_ads7950_probe(struct spi_device *spi)
spi_message_init_with_transfers(&st->scan_single_msg,
st->scan_single_xfer, 3);
st->reg = devm_regulator_get(&spi->dev, "refin");
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) {
dev_err(&spi->dev, "Failed get get regulator \"refin\"\n");
dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
return PTR_ERR(st->reg);
}
ret = regulator_enable(st->reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable regulator \"refin\"\n");
dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
return ret;
}
......@@ -459,25 +459,25 @@ static int ti_ads7950_remove(struct spi_device *spi)
}
static const struct spi_device_id ti_ads7950_id[] = {
{"ti-ads7950", TI_ADS7950},
{"ti-ads7951", TI_ADS7951},
{"ti-ads7952", TI_ADS7952},
{"ti-ads7953", TI_ADS7953},
{"ti-ads7954", TI_ADS7954},
{"ti-ads7955", TI_ADS7955},
{"ti-ads7956", TI_ADS7956},
{"ti-ads7957", TI_ADS7957},
{"ti-ads7958", TI_ADS7958},
{"ti-ads7959", TI_ADS7959},
{"ti-ads7960", TI_ADS7960},
{"ti-ads7961", TI_ADS7961},
{ "ads7950", TI_ADS7950 },
{ "ads7951", TI_ADS7951 },
{ "ads7952", TI_ADS7952 },
{ "ads7953", TI_ADS7953 },
{ "ads7954", TI_ADS7954 },
{ "ads7955", TI_ADS7955 },
{ "ads7956", TI_ADS7956 },
{ "ads7957", TI_ADS7957 },
{ "ads7958", TI_ADS7958 },
{ "ads7959", TI_ADS7959 },
{ "ads7960", TI_ADS7960 },
{ "ads7961", TI_ADS7961 },
{ }
};
MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
static struct spi_driver ti_ads7950_driver = {
.driver = {
.name = "ti-ads7950",
.name = "ads7950",
},
.probe = ti_ads7950_probe,
.remove = ti_ads7950_remove,
......
/*
* TI tlc4541 ADC Driver
*
* Copyright (C) 2017 Phil Reid
*
* Datasheets can be found here:
* http://www.ti.com/lit/gpn/tlc3541
* http://www.ti.com/lit/gpn/tlc4541
*
* 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.
*
* The tlc4541 requires 24 clock cycles to start a transfer.
* Conversion then takes 2.94us to complete before data is ready
* Data is returned MSB first.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
struct tlc4541_state {
struct spi_device *spi;
struct regulator *reg;
struct spi_transfer scan_single_xfer[3];
struct spi_message scan_single_msg;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
* 2 bytes data + 6 bytes padding + 8 bytes timestamp when
* call iio_push_to_buffers_with_timestamp.
*/
__be16 rx_buf[8] ____cacheline_aligned;
};
struct tlc4541_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
enum tlc4541_id {
TLC3541,
TLC4541,
};
#define TLC4541_V_CHAN(bits, bitshift) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
.shift = (bitshift), \
.endianness = IIO_BE, \
}, \
}
#define DECLARE_TLC4541_CHANNELS(name, bits, bitshift) \
const struct iio_chan_spec name ## _channels[] = { \
TLC4541_V_CHAN(bits, bitshift), \
IIO_CHAN_SOFT_TIMESTAMP(1), \
}
static DECLARE_TLC4541_CHANNELS(tlc3541, 14, 2);
static DECLARE_TLC4541_CHANNELS(tlc4541, 16, 0);
static const struct tlc4541_chip_info tlc4541_chip_info[] = {
[TLC3541] = {
.channels = tlc3541_channels,
.num_channels = ARRAY_SIZE(tlc3541_channels),
},
[TLC4541] = {
.channels = tlc4541_channels,
.num_channels = ARRAY_SIZE(tlc4541_channels),
},
};
static irqreturn_t tlc4541_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct tlc4541_state *st = iio_priv(indio_dev);
int ret;
ret = spi_sync(st->spi, &st->scan_single_msg);
if (ret < 0)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
iio_get_time_ns(indio_dev));
done:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int tlc4541_get_range(struct tlc4541_state *st)
{
int vref;
vref = regulator_get_voltage(st->reg);
if (vref < 0)
return vref;
vref /= 1000;
return vref;
}
static int tlc4541_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
int ret = 0;
struct tlc4541_state *st = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = spi_sync(st->spi, &st->scan_single_msg);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = be16_to_cpu(st->rx_buf[0]);
*val = *val >> chan->scan_type.shift;
*val &= GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = tlc4541_get_range(st);
if (ret < 0)
return ret;
*val = ret;
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
}
static const struct iio_info tlc4541_info = {
.read_raw = &tlc4541_read_raw,
.driver_module = THIS_MODULE,
};
static int tlc4541_probe(struct spi_device *spi)
{
struct tlc4541_state *st;
struct iio_dev *indio_dev;
const struct tlc4541_chip_info *info;
int ret;
int8_t device_init = 0;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
info = &tlc4541_chip_info[spi_get_device_id(spi)->driver_data];
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = info->channels;
indio_dev->num_channels = info->num_channels;
indio_dev->info = &tlc4541_info;
/* perform reset */
spi_write(spi, &device_init, 1);
/* Setup default message */
st->scan_single_xfer[0].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[0].len = 3;
st->scan_single_xfer[1].delay_usecs = 3;
st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
st->scan_single_xfer[2].len = 2;
spi_message_init_with_transfers(&st->scan_single_msg,
st->scan_single_xfer, 3);
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg))
return PTR_ERR(st->reg);
ret = regulator_enable(st->reg);
if (ret)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&tlc4541_trigger_handler, NULL);
if (ret)
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_buffer;
return 0;
error_cleanup_buffer:
iio_triggered_buffer_cleanup(indio_dev);
error_disable_reg:
regulator_disable(st->reg);
return ret;
}
static int tlc4541_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct tlc4541_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
regulator_disable(st->reg);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id tlc4541_dt_ids[] = {
{ .compatible = "ti,tlc3541", },
{ .compatible = "ti,tlc4541", },
{}
};
MODULE_DEVICE_TABLE(of, tlc4541_dt_ids);
#endif
static const struct spi_device_id tlc4541_id[] = {
{"tlc3541", TLC3541},
{"tlc4541", TLC4541},
{}
};
MODULE_DEVICE_TABLE(spi, tlc4541_id);
static struct spi_driver tlc4541_driver = {
.driver = {
.name = "tlc4541",
.of_match_table = of_match_ptr(tlc4541_dt_ids),
},
.probe = tlc4541_probe,
.remove = tlc4541_remove,
.id_table = tlc4541_id,
};
module_spi_driver(tlc4541_driver);
MODULE_AUTHOR("Phil Reid <preid@electromag.com.au>");
MODULE_DESCRIPTION("Texas Instruments TLC4541 ADC");
MODULE_LICENSE("GPL v2");
......@@ -378,7 +378,7 @@ static int max30100_get_temp(struct max30100_data *data, int *val)
if (ret)
return ret;
usleep_range(35000, 50000);
msleep(35);
return max30100_read_temp(data, val);
}
......
......@@ -39,6 +39,7 @@ config KMX61
be called kmx61.
source "drivers/iio/imu/inv_mpu6050/Kconfig"
source "drivers/iio/imu/st_lsm6dsx/Kconfig"
endmenu
......
......@@ -17,3 +17,5 @@ obj-y += bmi160/
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o
obj-y += st_lsm6dsx/
......@@ -325,9 +325,9 @@ static int bmi160_get_data(struct bmi160_data *data, int chan_type,
__le16 sample;
enum bmi160_sensor_type t = bmi160_to_sensor(chan_type);
reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16);
reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(sample);
ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16));
ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(sample));
if (ret < 0)
return ret;
......@@ -392,8 +392,8 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
for_each_set_bit(i, indio_dev->active_scan_mask,
indio_dev->masklength) {
ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16),
&sample, sizeof(__le16));
ret = regmap_bulk_read(data->regmap, base + i * sizeof(sample),
&sample, sizeof(sample));
if (ret < 0)
goto done;
buf[j++] = sample;
......
config IIO_ST_LSM6DSX
tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors"
depends on (I2C || SPI)
select IIO_BUFFER
select IIO_KFIFO_BUF
select IIO_ST_LSM6DSX_I2C if (I2C)
select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6dsm
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
config IIO_ST_LSM6DSX_I2C
tristate
depends on IIO_ST_LSM6DSX
config IIO_ST_LSM6DSX_SPI
tristate
depends on IIO_ST_LSM6DSX
st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o
obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o
/*
* STMicroelectronics st_lsm6dsx sensor driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#ifndef ST_LSM6DSX_H
#define ST_LSM6DSX_H
#include <linux/device.h>
#define ST_LSM6DS3_DEV_NAME "lsm6ds3"
#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
ST_LSM6DSM_ID,
};
#define ST_LSM6DSX_CHAN_SIZE 2
#define ST_LSM6DSX_SAMPLE_SIZE 6
#define ST_LSM6DSX_SAMPLE_DEPTH (ST_LSM6DSX_SAMPLE_SIZE / \
ST_LSM6DSX_CHAN_SIZE)
#if defined(CONFIG_SPI_MASTER)
#define ST_LSM6DSX_RX_MAX_LENGTH 256
#define ST_LSM6DSX_TX_MAX_LENGTH 8
struct st_lsm6dsx_transfer_buffer {
u8 rx_buf[ST_LSM6DSX_RX_MAX_LENGTH];
u8 tx_buf[ST_LSM6DSX_TX_MAX_LENGTH] ____cacheline_aligned;
};
#endif /* CONFIG_SPI_MASTER */
struct st_lsm6dsx_transfer_function {
int (*read)(struct device *dev, u8 addr, int len, u8 *data);
int (*write)(struct device *dev, u8 addr, int len, u8 *data);
};
struct st_lsm6dsx_reg {
u8 addr;
u8 mask;
};
struct st_lsm6dsx_settings {
u8 wai;
u16 max_fifo_size;
enum st_lsm6dsx_hw_id id;
};
enum st_lsm6dsx_sensor_id {
ST_LSM6DSX_ID_ACC,
ST_LSM6DSX_ID_GYRO,
ST_LSM6DSX_ID_MAX,
};
enum st_lsm6dsx_fifo_mode {
ST_LSM6DSX_FIFO_BYPASS = 0x0,
ST_LSM6DSX_FIFO_CONT = 0x6,
};
/**
* struct st_lsm6dsx_sensor - ST IMU sensor instance
* @id: Sensor identifier.
* @hw: Pointer to instance of struct st_lsm6dsx_hw.
* @gain: Configured sensor sensitivity.
* @odr: Output data rate of the sensor [Hz].
* @watermark: Sensor watermark level.
* @sip: Number of samples in a given pattern.
* @decimator: FIFO decimation factor.
* @decimator_mask: Sensor mask for decimation register.
* @delta_ts: Delta time between two consecutive interrupts.
* @ts: Latest timestamp from the interrupt handler.
*/
struct st_lsm6dsx_sensor {
enum st_lsm6dsx_sensor_id id;
struct st_lsm6dsx_hw *hw;
u32 gain;
u16 odr;
u16 watermark;
u8 sip;
u8 decimator;
u8 decimator_mask;
s64 delta_ts;
s64 ts;
};
/**
* struct st_lsm6dsx_hw - ST IMU MEMS hw instance
* @dev: Pointer to instance of struct device (I2C or SPI).
* @irq: Device interrupt line (I2C or SPI).
* @lock: Mutex to protect read and write operations.
* @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
* @fifo_mode: FIFO operating mode supported by the device.
* @enable_mask: Enabled sensor bitmask.
* @sip: Total number of samples (acc/gyro) in a given pattern.
* @iio_devs: Pointers to acc/gyro iio_dev instances.
* @settings: Pointer to the specific sensor settings in use.
* @tf: Transfer function structure used by I/O operations.
* @tb: Transfer buffers used by SPI I/O operations.
*/
struct st_lsm6dsx_hw {
struct device *dev;
int irq;
struct mutex lock;
struct mutex fifo_lock;
enum st_lsm6dsx_fifo_mode fifo_mode;
u8 enable_mask;
u8 sip;
struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
const struct st_lsm6dsx_settings *settings;
const struct st_lsm6dsx_transfer_function *tf;
#if defined(CONFIG_SPI_MASTER)
struct st_lsm6dsx_transfer_buffer tb;
#endif /* CONFIG_SPI_MASTER */
};
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
const struct st_lsm6dsx_transfer_function *tf_ops);
int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
u8 val);
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
u16 watermark);
#endif /* ST_LSM6DSX_H */
This diff is collapsed.
This diff is collapsed.
/*
* STMicroelectronics st_lsm6dsx i2c driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "st_lsm6dsx.h"
static int st_lsm6dsx_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msg[2];
msg[0].addr = client->addr;
msg[0].flags = client->flags;
msg[0].len = 1;
msg[0].buf = &addr;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = len;
msg[1].buf = data;
return i2c_transfer(client->adapter, msg, 2);
}
static int st_lsm6dsx_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_msg msg;
u8 send[len + 1];
send[0] = addr;
memcpy(&send[1], data, len * sizeof(u8));
msg.addr = client->addr;
msg.flags = client->flags;
msg.len = len + 1;
msg.buf = send;
return i2c_transfer(client->adapter, &msg, 1);
}
static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
.read = st_lsm6dsx_i2c_read,
.write = st_lsm6dsx_i2c_write,
};
static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
return st_lsm6dsx_probe(&client->dev, client->irq,
(int)id->driver_data,
&st_lsm6dsx_transfer_fn);
}
static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
{
.compatible = "st,lsm6ds3",
.data = (void *)ST_LSM6DS3_ID,
},
{
.compatible = "st,lsm6dsm",
.data = (void *)ST_LSM6DSM_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
static struct i2c_driver st_lsm6dsx_driver = {
.driver = {
.name = "st_lsm6dsx_i2c",
.of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
},
.probe = st_lsm6dsx_i2c_probe,
.id_table = st_lsm6dsx_i2c_id_table,
};
module_i2c_driver(st_lsm6dsx_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i2c driver");
MODULE_LICENSE("GPL v2");
/*
* STMicroelectronics st_lsm6dsx spi driver
*
* Copyright 2016 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
* Denis Ciocca <denis.ciocca@st.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "st_lsm6dsx.h"
#define SENSORS_SPI_READ BIT(7)
static int st_lsm6dsx_spi_read(struct device *dev, u8 addr, int len,
u8 *data)
{
struct spi_device *spi = to_spi_device(dev);
struct st_lsm6dsx_hw *hw = spi_get_drvdata(spi);
int err;
struct spi_transfer xfers[] = {
{
.tx_buf = hw->tb.tx_buf,
.bits_per_word = 8,
.len = 1,
},
{
.rx_buf = hw->tb.rx_buf,
.bits_per_word = 8,
.len = len,
}
};
hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
if (err < 0)
return err;
memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
return len;
}
static int st_lsm6dsx_spi_write(struct device *dev, u8 addr, int len,
u8 *data)
{
struct st_lsm6dsx_hw *hw;
struct spi_device *spi;
if (len >= ST_LSM6DSX_TX_MAX_LENGTH)
return -ENOMEM;
spi = to_spi_device(dev);
hw = spi_get_drvdata(spi);
hw->tb.tx_buf[0] = addr;
memcpy(&hw->tb.tx_buf[1], data, len);
return spi_write(spi, hw->tb.tx_buf, len + 1);
}
static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
.read = st_lsm6dsx_spi_read,
.write = st_lsm6dsx_spi_write,
};
static int st_lsm6dsx_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
return st_lsm6dsx_probe(&spi->dev, spi->irq,
(int)id->driver_data,
&st_lsm6dsx_transfer_fn);
}
static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
{
.compatible = "st,lsm6ds3",
.data = (void *)ST_LSM6DS3_ID,
},
{
.compatible = "st,lsm6dsm",
.data = (void *)ST_LSM6DSM_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
{ ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
static struct spi_driver st_lsm6dsx_driver = {
.driver = {
.name = "st_lsm6dsx_spi",
.of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
},
.probe = st_lsm6dsx_spi_probe,
.id_table = st_lsm6dsx_spi_id_table,
};
module_spi_driver(st_lsm6dsx_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx spi driver");
MODULE_LICENSE("GPL v2");
......@@ -147,8 +147,7 @@ static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
return NULL;
}
static struct iio_trigger *iio_trigger_find_by_name(const char *name,
size_t len)
static struct iio_trigger *iio_trigger_acquire_by_name(const char *name)
{
struct iio_trigger *trig = NULL, *iter;
......@@ -156,6 +155,7 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name,
list_for_each_entry(iter, &iio_trigger_list, list)
if (sysfs_streq(iter->name, name)) {
trig = iter;
iio_trigger_get(trig);
break;
}
mutex_unlock(&iio_trigger_list_lock);
......@@ -416,20 +416,22 @@ static ssize_t iio_trigger_write_current(struct device *dev,
}
mutex_unlock(&indio_dev->mlock);
trig = iio_trigger_find_by_name(buf, len);
if (oldtrig == trig)
return len;
trig = iio_trigger_acquire_by_name(buf);
if (oldtrig == trig) {
ret = len;
goto out_trigger_put;
}
if (trig && indio_dev->info->validate_trigger) {
ret = indio_dev->info->validate_trigger(indio_dev, trig);
if (ret)
return ret;
goto out_trigger_put;
}
if (trig && trig->ops->validate_device) {
ret = trig->ops->validate_device(trig, indio_dev);
if (ret)
return ret;
goto out_trigger_put;
}
indio_dev->trig = trig;
......@@ -441,13 +443,16 @@ static ssize_t iio_trigger_write_current(struct device *dev,
iio_trigger_put(oldtrig);
}
if (indio_dev->trig) {
iio_trigger_get(indio_dev->trig);
if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
iio_trigger_attach_poll_func(indio_dev->trig,
indio_dev->pollfunc_event);
}
return len;
out_trigger_put:
iio_trigger_put(trig);
return ret;
}
static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR,
......@@ -487,7 +492,7 @@ static void iio_trig_release(struct device *device)
kfree(trig);
}
static struct device_type iio_trig_type = {
static const struct device_type iio_trig_type = {
.release = iio_trig_release,
.groups = iio_trig_dev_groups,
};
......@@ -513,46 +518,45 @@ static void iio_trig_subirqunmask(struct irq_data *d)
static struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs)
{
struct iio_trigger *trig;
int i;
trig = kzalloc(sizeof *trig, GFP_KERNEL);
if (trig) {
int i;
trig->dev.type = &iio_trig_type;
trig->dev.bus = &iio_bus_type;
device_initialize(&trig->dev);
mutex_init(&trig->pool_lock);
trig->subirq_base
= irq_alloc_descs(-1, 0,
CONFIG_IIO_CONSUMERS_PER_TRIGGER,
0);
if (trig->subirq_base < 0) {
kfree(trig);
return NULL;
}
if (!trig)
return NULL;
trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
if (trig->name == NULL) {
irq_free_descs(trig->subirq_base,
CONFIG_IIO_CONSUMERS_PER_TRIGGER);
kfree(trig);
return NULL;
}
trig->subirq_chip.name = trig->name;
trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
irq_set_chip(trig->subirq_base + i,
&trig->subirq_chip);
irq_set_handler(trig->subirq_base + i,
&handle_simple_irq);
irq_modify_status(trig->subirq_base + i,
IRQ_NOREQUEST | IRQ_NOAUTOEN,
IRQ_NOPROBE);
}
get_device(&trig->dev);
trig->dev.type = &iio_trig_type;
trig->dev.bus = &iio_bus_type;
device_initialize(&trig->dev);
mutex_init(&trig->pool_lock);
trig->subirq_base = irq_alloc_descs(-1, 0,
CONFIG_IIO_CONSUMERS_PER_TRIGGER,
0);
if (trig->subirq_base < 0)
goto free_trig;
trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
if (trig->name == NULL)
goto free_descs;
trig->subirq_chip.name = trig->name;
trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
irq_set_chip(trig->subirq_base + i, &trig->subirq_chip);
irq_set_handler(trig->subirq_base + i, &handle_simple_irq);
irq_modify_status(trig->subirq_base + i,
IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
}
get_device(&trig->dev);
return trig;
free_descs:
irq_free_descs(trig->subirq_base, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
free_trig:
kfree(trig);
return NULL;
}
struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
......
......@@ -601,8 +601,14 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
IIO_CHAN_INFO_SCALE);
if (scale_type < 0)
return scale_type;
if (scale_type < 0) {
/*
* Just pass raw values as processed if no scaling is
* available.
*/
*processed = raw;
return 0;
}
switch (scale_type) {
case IIO_VAL_INT:
......
......@@ -278,7 +278,7 @@ static int cm3605_remove(struct platform_device *pdev)
return 0;
}
static int cm3605_pm_suspend(struct device *dev)
static int __maybe_unused cm3605_pm_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct cm3605 *cm3605 = iio_priv(indio_dev);
......@@ -289,7 +289,7 @@ static int cm3605_pm_suspend(struct device *dev)
return 0;
}
static int cm3605_pm_resume(struct device *dev)
static int __maybe_unused cm3605_pm_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct cm3605 *cm3605 = iio_priv(indio_dev);
......
......@@ -840,6 +840,7 @@ static const struct of_device_id opt3001_of_match[] = {
{ .compatible = "ti,opt3001" },
{ }
};
MODULE_DEVICE_TABLE(of, opt3001_of_match);
static struct i2c_driver opt3001_driver = {
.probe = opt3001_probe,
......
......@@ -278,13 +278,9 @@ static int ak8974_await_drdy(struct ak8974 *ak8974)
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;
dev_err(&ak8974->i2c->dev, "timeout waiting for DRDY\n");
return -ETIMEDOUT;
}
static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result)
......
......@@ -222,29 +222,39 @@ static int mag3110_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct mag3110_data *data = iio_priv(indio_dev);
int rate;
int rate, ret;
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
rate = mag3110_get_samp_freq_index(data, val, val2);
if (rate < 0)
return -EINVAL;
if (rate < 0) {
ret = -EINVAL;
break;
}
data->ctrl_reg1 &= ~MAG3110_CTRL_DR_MASK;
data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT;
return i2c_smbus_write_byte_data(data->client,
ret = i2c_smbus_write_byte_data(data->client,
MAG3110_CTRL_REG1, data->ctrl_reg1);
break;
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -10000 || val > 10000)
return -EINVAL;
return i2c_smbus_write_word_swapped(data->client,
if (val < -10000 || val > 10000) {
ret = -EINVAL;
break;
}
ret = i2c_smbus_write_word_swapped(data->client,
MAG3110_OFF_X + 2 * chan->scan_index, val << 1);
break;
default:
return -EINVAL;
ret = -EINVAL;
break;
}
iio_device_release_direct_mode(indio_dev);
return ret;
}
static irqreturn_t mag3110_trigger_handler(int irq, void *p)
......
......@@ -284,6 +284,7 @@ static const struct of_device_id mcp4531_of_match[] = {
MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104),
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mcp4531_of_match);
#endif
static int mcp4531_probe(struct i2c_client *client,
......
......@@ -308,6 +308,7 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
{
struct ms5611_state *st = iio_priv(indio_dev);
const struct ms5611_osr *osr = NULL;
int ret;
if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
return -EINVAL;
......@@ -321,12 +322,11 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
if (!osr)
return -EINVAL;
mutex_lock(&st->lock);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&st->lock);
return -EBUSY;
}
mutex_lock(&st->lock);
if (chan->type == IIO_TEMP)
st->temp_osr = osr;
......@@ -334,6 +334,8 @@ static int ms5611_write_raw(struct iio_dev *indio_dev,
st->pressure_osr = osr;
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
return 0;
}
......
......@@ -387,14 +387,18 @@ static int sx9500_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct sx9500_data *data = iio_priv(indio_dev);
int ret;
switch (chan->type) {
case IIO_PROXIMITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
return sx9500_read_proximity(data, chan, val);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = sx9500_read_proximity(data, chan, val);
iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9500_read_samp_freq(data, val, val2);
default:
......
......@@ -39,6 +39,16 @@ config TMP006
This driver can also be built as a module. If so, the module will
be called tmp006.
config TMP007
tristate "TMP007 infrared thermopile sensor with Integrated Math Engine"
depends on I2C
help
If you say yes here you get support for the Texas Instruments
TMP007 infrared thermopile sensor with Integrated Math Engine.
This driver can also be built as a module. If so, the module will
be called tmp007.
config TSYS01
tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
depends on I2C
......
......@@ -5,5 +5,6 @@
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TSYS01) += tsys01.o
obj-$(CONFIG_TSYS02D) += tsys02d.o
/*
* tmp007.c - Support for TI TMP007 IR thermopile sensor with integrated math engine
*
* Copyright (c) 2017 Manivannan Sadhasivam <manivannanece23@gmail.com>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
*
* (7-bit I2C slave address (0x40 - 0x47), changeable via ADR pins)
*
* Note: This driver assumes that the sensor has been calibrated beforehand
*
* TODO: ALERT irq, limit threshold events
*
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/bitops.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define TMP007_TDIE 0x01
#define TMP007_CONFIG 0x02
#define TMP007_TOBJECT 0x03
#define TMP007_STATUS 0x04
#define TMP007_STATUS_MASK 0x05
#define TMP007_MANUFACTURER_ID 0x1e
#define TMP007_DEVICE_ID 0x1f
#define TMP007_CONFIG_CONV_EN BIT(12)
#define TMP007_CONFIG_COMP_EN BIT(5)
#define TMP007_CONFIG_TC_EN BIT(6)
#define TMP007_CONFIG_CR_MASK GENMASK(11, 9)
#define TMP007_CONFIG_CR_SHIFT 9
#define TMP007_STATUS_CONV_READY BIT(14)
#define TMP007_STATUS_DATA_VALID BIT(9)
#define TMP007_MANUFACTURER_MAGIC 0x5449
#define TMP007_DEVICE_MAGIC 0x0078
#define TMP007_TEMP_SHIFT 2
struct tmp007_data {
struct i2c_client *client;
u16 config;
};
static const int tmp007_avgs[5][2] = { {4, 0}, {2, 0}, {1, 0},
{0, 500000}, {0, 250000} };
static int tmp007_read_temperature(struct tmp007_data *data, u8 reg)
{
s32 ret;
int tries = 50;
while (tries-- > 0) {
ret = i2c_smbus_read_word_swapped(data->client,
TMP007_STATUS);
if (ret < 0)
return ret;
if ((ret & TMP007_STATUS_CONV_READY) &&
!(ret & TMP007_STATUS_DATA_VALID))
break;
msleep(100);
}
if (tries < 0)
return -EIO;
return i2c_smbus_read_word_swapped(data->client, reg);
}
static int tmp007_powerdown(struct tmp007_data *data)
{
return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
data->config & ~TMP007_CONFIG_CONV_EN);
}
static int tmp007_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct tmp007_data *data = iio_priv(indio_dev);
s32 ret;
int conv_rate;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (channel->channel2) {
case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.03125 degree Celsius */
ret = i2c_smbus_read_word_swapped(data->client, TMP007_TDIE);
if (ret < 0)
return ret;
break;
case IIO_MOD_TEMP_OBJECT:
ret = tmp007_read_temperature(data, TMP007_TOBJECT);
if (ret < 0)
return ret;
break;
default:
return -EINVAL;
}
*val = sign_extend32(ret, 15) >> TMP007_TEMP_SHIFT;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 31;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
conv_rate = (data->config & TMP007_CONFIG_CR_MASK)
>> TMP007_CONFIG_CR_SHIFT;
*val = tmp007_avgs[conv_rate][0];
*val2 = tmp007_avgs[conv_rate][1];
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int tmp007_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int val,
int val2, long mask)
{
struct tmp007_data *data = iio_priv(indio_dev);
int i;
u16 tmp;
if (mask == IIO_CHAN_INFO_SAMP_FREQ) {
for (i = 0; i < ARRAY_SIZE(tmp007_avgs); i++) {
if ((val == tmp007_avgs[i][0]) &&
(val2 == tmp007_avgs[i][1])) {
tmp = data->config & ~TMP007_CONFIG_CR_MASK;
tmp |= (i << TMP007_CONFIG_CR_SHIFT);
return i2c_smbus_write_word_swapped(data->client,
TMP007_CONFIG,
data->config = tmp);
}
}
}
return -EINVAL;
}
static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
static struct attribute *tmp007_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group tmp007_attribute_group = {
.attrs = tmp007_attributes,
};
static const struct iio_chan_spec tmp007_channels[] = {
{
.type = IIO_TEMP,
.modified = 1,
.channel2 = IIO_MOD_TEMP_AMBIENT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_TEMP,
.modified = 1,
.channel2 = IIO_MOD_TEMP_OBJECT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
}
};
static const struct iio_info tmp007_info = {
.read_raw = tmp007_read_raw,
.write_raw = tmp007_write_raw,
.attrs = &tmp007_attribute_group,
.driver_module = THIS_MODULE,
};
static bool tmp007_identify(struct i2c_client *client)
{
int manf_id, dev_id;
manf_id = i2c_smbus_read_word_swapped(client, TMP007_MANUFACTURER_ID);
if (manf_id < 0)
return false;
dev_id = i2c_smbus_read_word_swapped(client, TMP007_DEVICE_ID);
if (dev_id < 0)
return false;
return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC);
}
static int tmp007_probe(struct i2c_client *client,
const struct i2c_device_id *tmp007_id)
{
struct tmp007_data *data;
struct iio_dev *indio_dev;
int ret;
u16 status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
if (!tmp007_identify(client)) {
dev_err(&client->dev, "TMP007 not found\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
indio_dev->dev.parent = &client->dev;
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &tmp007_info;
indio_dev->channels = tmp007_channels;
indio_dev->num_channels = ARRAY_SIZE(tmp007_channels);
/*
* Set Configuration register:
* 1. Conversion ON
* 2. Comparator mode
* 3. Transient correction enable
*/
ret = i2c_smbus_read_word_swapped(data->client, TMP007_CONFIG);
if (ret < 0)
return ret;
data->config = ret;
data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_COMP_EN | TMP007_CONFIG_TC_EN);
ret = i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
data->config);
if (ret < 0)
return ret;
/*
* Set Status Mask register:
* 1. Conversion ready enable
* 2. Data valid enable
*/
ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
if (ret < 0)
goto error_powerdown;
status = ret;
status |= (TMP007_STATUS_CONV_READY | TMP007_STATUS_DATA_VALID);
ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, status);
if (ret < 0)
goto error_powerdown;
return iio_device_register(indio_dev);
error_powerdown:
tmp007_powerdown(data);
return ret;
}
static int tmp007_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct tmp007_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
tmp007_powerdown(data);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int tmp007_suspend(struct device *dev)
{
struct tmp007_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return tmp007_powerdown(data);
}
static int tmp007_resume(struct device *dev)
{
struct tmp007_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
data->config | TMP007_CONFIG_CONV_EN);
}
#endif
static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
static const struct of_device_id tmp007_of_match[] = {
{ .compatible = "ti,tmp007", },
{ },
};
MODULE_DEVICE_TABLE(of, tmp007_of_match);
static const struct i2c_device_id tmp007_id[] = {
{ "tmp007", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp007_id);
static struct i2c_driver tmp007_driver = {
.driver = {
.name = "tmp007",
.of_match_table = of_match_ptr(tmp007_of_match),
.pm = &tmp007_pm_ops,
},
.probe = tmp007_probe,
.remove = tmp007_remove,
.id_table = tmp007_id,
};
module_i2c_driver(tmp007_driver);
MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
MODULE_DESCRIPTION("TI TMP007 IR thermopile sensor driver");
MODULE_LICENSE("GPL");
......@@ -58,7 +58,7 @@ static int iio_interrupt_trigger_probe(struct platform_device *pdev)
trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
if (!trig_info) {
ret = -ENOMEM;
goto error_put_trigger;
goto error_free_trigger;
}
iio_trigger_set_drvdata(trig, trig_info);
trig_info->irq = irq;
......@@ -83,8 +83,8 @@ static int iio_interrupt_trigger_probe(struct platform_device *pdev)
free_irq(irq, trig);
error_free_trig_info:
kfree(trig_info);
error_put_trigger:
iio_trigger_put(trig);
error_free_trigger:
iio_trigger_free(trig);
error_ret:
return ret;
}
......@@ -99,7 +99,7 @@ static int iio_interrupt_trigger_remove(struct platform_device *pdev)
iio_trigger_unregister(trig);
free_irq(trig_info->irq, trig);
kfree(trig_info);
iio_trigger_put(trig);
iio_trigger_free(trig);
return 0;
}
......
......@@ -174,7 +174,7 @@ static int iio_sysfs_trigger_probe(int id)
return 0;
out2:
iio_trigger_put(t->trig);
iio_trigger_free(t->trig);
free_t:
kfree(t);
out1:
......
This diff is collapsed.
......@@ -260,7 +260,7 @@ static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
out1:
iio_trigger_unregister(st->trig);
out:
iio_trigger_put(st->trig);
iio_trigger_free(st->trig);
return ret;
}
......@@ -273,7 +273,7 @@ static int iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
peripheral_free(st->t->pin);
free_irq(st->irq, st);
iio_trigger_unregister(st->trig);
iio_trigger_put(st->trig);
iio_trigger_free(st->trig);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment