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

Merge tag 'iio-for-4.15b' of...

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

Jonathan writes:

Second set of IIO new device support, features and cleanup for 4.15

New device support
* cros_ec_accel_legacy
  - New driver for this older chromebook accelerometer.
* ds4422 dac driver
  - New driver and bindings for the Maxim ds4422 and ds4424 I2C DACs.
* kxcjk1013
  - Support the KXTF9 accelerometers.
* mcp320x
  - support mcp3550, mcp3551, mcp3553 21 bit ADCs.
* rfd77402
  - new driver for this laser range finder.
* st-sensors-accel
  - add support for the LIS2DW12 accelerometer with bindings
  - add support for the LIS3DHH accelerometer with bindings

New features
* core
  - Drop a duplicate forward declaration in iio.h
* Docs
  - add a clarification of the meaning of IIO_DISTANCE to reflect
    existing use in various range finding devices.
* st-sensors
  - add a register mask for the status register to correctly support
    2 channel devices.
  - decouple the irq1 and irq2 configuration parameters.
  - do not always write the enable_axis register as some newer devices
    are always on and don't support such configuration.
  - split open-drain control for irq1 and irq2
  - make sampling frequency control optional as non all hardware
    supports it.
* st-sensors-gyro
  - support 3 wire SPI mode
* st-sensors-magn
  - support 3 wire SPI mode
* st-sensors-pressure
  - support 3 wire SPI mode.

Cleanups and fixes
* ad7192
  - expand the buffer lock to cover device state protection rather than
    using core mlock to provide the state protection.
* ade7753
  - expand the buffer lock to cover device state protection as well
    rather than having an additional lock.
* dummy-evgen
  - Use the new irq_sim infrastructure rather than having our
    own local version of the same thing.
* hid-sensor-trigger
  - avoid touching sensors ever if user hasn't requested it.  This
    is a work around for one reported issue where turning a sensor
    off wasn't sufficient to make it actually switch off.  As we
    have only one report from what looks like buggy hardware we
    are sending this upstream the slow way.
* ina2xx
  - Adhere to the published ABI docs and use Ohms instead of
    microohms.  We don't think that anyone will notice this ABI fix
    but are sending it the slow route to reduce fallout if someone
    does!
* kxcjk1013 - refactors to support the KXTF9 being added.
  - Refactor ODR support.
  - Fix INT_CTRL/INT_SRC1 bit names to match the register name.
  - Extract code for reporting motion events as this isn't present
    on some parts to be supported.
  - Make the sysfs sampling_frequency_available stuff not a fixed
    string so as to allow for it to be chip type dependent.
  - Make the sampling frequency_available per type to match
    the sampling_frequency attributes.
* lsm6dsx - rework prior to new device support.
  - express the max fifo depth in 'scans' rather than bytes.
  - split control of the fifo mode fifo output data rate.
  - move decimator registers into the sensor_settings structure
    as this will make it easier to support devices that don't have
    this function.
  - add a fifo ops datastructure to allow for inter-part variations.
* max30100
  - fix i2c chip address in dt example
* max30102
  - use correct binding name for max30102 in example
* mma8452
  - Rename read/write event value callbacks to be more generic
    reflecting what they actually do now.
* rcar-gyroadc
  - pointer case to fix warnings when moving to 64 bit as this IP is
    present on new 64 bit SOCs
  - enable compile-testing to improve build coverage on this driver.
  - use the of_device_get_match_data helper instead of open coding
* sun4i-gpadc-iio
  - Register in the thermal framework after pm. Otherwise the IP is not
    enabled.
  - Don't fail probing if no thermal DT node is present.
* tsl2x7x
  - renaming tsl2x7x_settings to settings to avoid excessive line
    lengths.
  - Use IIO core to generate the integration_time sysfs attributes
    rather than hand rolling.
* vf6180
  - Move the range check on integration time to the setter function.
  - Refactor the code around integration time to be clearer including
    caching current integration time avoiding unnecessary chip reads.
  - cleanup the als_gain lookup avoiding reading registers on chip.
  - use rounded matching rather than precise values for als_gain
    lookup.
  - Correct the ALS  scale when non-default gain or integration time
    is used.
parents 1236d6bb 11b86c70
......@@ -1242,9 +1242,9 @@ What: /sys/.../iio:deviceX/in_distance_raw
KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to read the distance covered by the user
since the last reboot while activated. Units after application
of scale are meters.
This attribute is used to read the measured distance to an object
or the distance covered by the user since the last reboot while
activated. Units after application of scale are meters.
What: /sys/bus/iio/devices/iio:deviceX/store_eeprom
KernelVersion: 3.4.0
......
......@@ -16,3 +16,13 @@ Description:
the motion sensor is placed. For example, in a laptop a motion
sensor can be located on the base or on the lid. Current valid
values are 'base' and 'lid'.
What: /sys/bus/iio/devices/iio:deviceX/id
Date: Septembre 2017
KernelVersion: 4.14
Contact: linux-iio@vger.kernel.org
Description:
This attribute is exposed by the CrOS EC legacy accelerometer
driver and represents the sensor ID as exposed by the EC. This
ID is used by the Android sensor service hardware abstraction
layer (sensor HAL) through the Android container on ChromeOS.
Maxim Integrated DS4422/DS4424 7-bit Sink/Source Current DAC Device Driver
Datasheet publicly available at:
https://datasheets.maximintegrated.com/en/ds/DS4422-DS4424.pdf
Required properties:
- compatible: Should be one of
maxim,ds4422
maxim,ds4424
- reg: Should contain the DAC I2C address
Optional properties:
- vcc-supply: Power supply is optional. If not defined, driver will ignore it.
Example:
ds4224@10 {
compatible = "maxim,ds4424";
reg = <0x10>; /* When A0, A1 pins are ground */
vcc-supply = <&vcc_3v3>;
};
......@@ -20,9 +20,9 @@ Optional properties:
Example:
max30100@057 {
max30100@57 {
compatible = "maxim,max30100";
reg = <57>;
reg = <0x57>;
maxim,led-current-microamp = <24000 50000>;
interrupt-parent = <&gpio1>;
interrupts = <16 2>;
......
......@@ -20,7 +20,7 @@ Optional properties:
Example:
max30100@57 {
max30102@57 {
compatible = "maxim,max30102";
reg = <0x57>;
maxim,red-led-current-microamp = <7000>;
......
......@@ -46,6 +46,8 @@ Accelerometers:
- st,h3lis331dl-accel
- st,lng2dm-accel
- st,lis3l02dq
- st,lis2dw12
- st,lis3dhh
Gyroscopes:
- st,l3g4200d-gyro
......
......@@ -148,6 +148,17 @@ config HID_SENSOR_ACCEL_3D
To compile this driver as a module, choose M here: the
module will be called hid-sensor-accel-3d.
config IIO_CROS_EC_ACCEL_LEGACY
tristate "ChromeOS EC Legacy Accelerometer Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select CROS_EC_LPC_REGISTER_DEVICE
help
Say yes here to get support for accelerometers on Chromebook using
legacy EC firmware.
Sensor data is retrieved through IO memory.
Newer devices should use IIO_CROS_EC_SENSORS.
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
......@@ -219,8 +230,8 @@ config KXCJK1013
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Kionix KXCJK-1013
triaxial acceleration sensor. This driver also supports KXCJ9-1008
and KXTJ2-1009.
triaxial acceleration sensor. This driver also supports KXCJ9-1008,
KXTJ2-1009 and KXTF9.
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
......
......@@ -43,6 +43,8 @@ obj-$(CONFIG_SCA3000) += sca3000.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
obj-$(CONFIG_IIO_CROS_EC_ACCEL_LEGACY) += cros_ec_accel_legacy.o
obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
......
/*
* Driver for older Chrome OS EC accelerometer
*
* Copyright 2017 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 uses the memory mapper cros-ec interface to communicate
* with the Chrome OS EC about accelerometer data.
* Accelerometer access is presented through iio sysfs.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/kernel.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/platform_device.h>
#define DRV_NAME "cros-ec-accel-legacy"
/*
* Sensor scale hard coded at 10 bits per g, computed as:
* g / (2^10 - 1) = 0.009586168; with g = 9.80665 m.s^-2
*/
#define ACCEL_LEGACY_NSCALE 9586168
/* Indices for EC sensor values. */
enum {
X,
Y,
Z,
MAX_AXIS,
};
/* State data for cros_ec_accel_legacy iio driver. */
struct cros_ec_accel_legacy_state {
struct cros_ec_device *ec;
/*
* Array holding data from a single capture. 2 bytes per channel
* for the 3 channels plus the timestamp which is always last and
* 8-bytes aligned.
*/
s16 capture_data[8];
s8 sign[MAX_AXIS];
u8 sensor_num;
};
static int ec_cmd_read_u8(struct cros_ec_device *ec, unsigned int offset,
u8 *dest)
{
return ec->cmd_readmem(ec, offset, 1, dest);
}
static int ec_cmd_read_u16(struct cros_ec_device *ec, unsigned int offset,
u16 *dest)
{
__le16 tmp;
int ret = ec->cmd_readmem(ec, offset, 2, &tmp);
*dest = le16_to_cpu(tmp);
return ret;
}
/**
* read_ec_until_not_busy() - Read from EC status byte until it reads not busy.
* @st: Pointer to state information for device.
*
* This function reads EC status until its busy bit gets cleared. It does not
* wait indefinitely and returns -EIO if the EC status is still busy after a
* few hundreds milliseconds.
*
* Return: 8-bit status if ok, -EIO on error
*/
static int read_ec_until_not_busy(struct cros_ec_accel_legacy_state *st)
{
struct cros_ec_device *ec = st->ec;
u8 status;
int attempts = 0;
ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status);
while (status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) {
/* Give up after enough attempts, return error. */
if (attempts++ >= 50)
return -EIO;
/* Small delay every so often. */
if (attempts % 5 == 0)
msleep(25);
ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status);
}
return status;
}
/**
* read_ec_accel_data_unsafe() - Read acceleration data from EC shared memory.
* @st: Pointer to state information for device.
* @scan_mask: Bitmap of the sensor indices to scan.
* @data: Location to store data.
*
* This is the unsafe function for reading the EC data. It does not guarantee
* that the EC will not modify the data as it is being read in.
*/
static void read_ec_accel_data_unsafe(struct cros_ec_accel_legacy_state *st,
unsigned long scan_mask, s16 *data)
{
int i = 0;
int num_enabled = bitmap_weight(&scan_mask, MAX_AXIS);
/* Read all sensors enabled in scan_mask. Each value is 2 bytes. */
while (num_enabled--) {
i = find_next_bit(&scan_mask, MAX_AXIS, i);
ec_cmd_read_u16(st->ec,
EC_MEMMAP_ACC_DATA +
sizeof(s16) *
(1 + i + st->sensor_num * MAX_AXIS),
data);
*data *= st->sign[i];
i++;
data++;
}
}
/**
* read_ec_accel_data() - Read acceleration data from EC shared memory.
* @st: Pointer to state information for device.
* @scan_mask: Bitmap of the sensor indices to scan.
* @data: Location to store data.
*
* This is the safe function for reading the EC data. It guarantees that
* the data sampled was not modified by the EC while being read.
*
* Return: 0 if ok, -ve on error
*/
static int read_ec_accel_data(struct cros_ec_accel_legacy_state *st,
unsigned long scan_mask, s16 *data)
{
u8 samp_id = 0xff;
u8 status = 0;
int ret;
int attempts = 0;
/*
* Continually read all data from EC until the status byte after
* all reads reflects that the EC is not busy and the sample id
* matches the sample id from before all reads. This guarantees
* that data read in was not modified by the EC while reading.
*/
while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT |
EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) {
/* If we have tried to read too many times, return error. */
if (attempts++ >= 5)
return -EIO;
/* Read status byte until EC is not busy. */
ret = read_ec_until_not_busy(st);
if (ret < 0)
return ret;
status = ret;
/*
* Store the current sample id so that we can compare to the
* sample id after reading the data.
*/
samp_id = status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK;
/* Read all EC data, format it, and store it into data. */
read_ec_accel_data_unsafe(st, scan_mask, data);
/* Read status byte. */
ec_cmd_read_u8(st->ec, EC_MEMMAP_ACC_STATUS, &status);
}
return 0;
}
static int cros_ec_accel_legacy_read(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
s16 data = 0;
int ret = IIO_VAL_INT;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = read_ec_accel_data(st, (1 << chan->scan_index), &data);
if (ret)
return ret;
*val = data;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = ACCEL_LEGACY_NSCALE;
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_CALIBBIAS:
/* Calibration not supported. */
*val = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int cros_ec_accel_legacy_write(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
/*
* Do nothing but don't return an error code to allow calibration
* script to work.
*/
if (mask == IIO_CHAN_INFO_CALIBBIAS)
return 0;
return -EINVAL;
}
static const struct iio_info cros_ec_accel_legacy_info = {
.read_raw = &cros_ec_accel_legacy_read,
.write_raw = &cros_ec_accel_legacy_write,
};
/**
* cros_ec_accel_legacy_capture() - The trigger handler function
* @irq: The interrupt number.
* @p: Private data - always a pointer to the poll func.
*
* On a trigger event occurring, if the pollfunc is attached then this
* handler is called as a threaded interrupt (and hence may sleep). It
* is responsible for grabbing data from the device and pushing it into
* the associated buffer.
*
* Return: IRQ_HANDLED
*/
static irqreturn_t cros_ec_accel_legacy_capture(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
/* Clear capture data. */
memset(st->capture_data, 0, sizeof(st->capture_data));
/*
* Read data based on which channels are enabled in scan mask. Note
* that on a capture we are always reading the calibrated data.
*/
read_ec_accel_data(st, *indio_dev->active_scan_mask, st->capture_data);
iio_push_to_buffers_with_timestamp(indio_dev, (void *)st->capture_data,
iio_get_time_ns(indio_dev));
/*
* Tell the core we are done with this trigger and ready for the
* next one.
*/
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static char *cros_ec_accel_legacy_loc_strings[] = {
[MOTIONSENSE_LOC_BASE] = "base",
[MOTIONSENSE_LOC_LID] = "lid",
[MOTIONSENSE_LOC_MAX] = "unknown",
};
static ssize_t cros_ec_accel_legacy_loc(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
return sprintf(buf, "%s\n",
cros_ec_accel_legacy_loc_strings[st->sensor_num +
MOTIONSENSE_LOC_BASE]);
}
static ssize_t cros_ec_accel_legacy_id(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->sensor_num);
}
static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = {
{
.name = "id",
.shared = IIO_SHARED_BY_ALL,
.read = cros_ec_accel_legacy_id,
},
{
.name = "location",
.shared = IIO_SHARED_BY_ALL,
.read = cros_ec_accel_legacy_loc,
},
{ }
};
#define CROS_EC_ACCEL_LEGACY_CHAN(_axis) \
{ \
.type = IIO_ACCEL, \
.channel2 = IIO_MOD_X + (_axis), \
.modified = 1, \
.info_mask_separate = \
BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = cros_ec_accel_legacy_ext_info, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
}, \
} \
static struct iio_chan_spec ec_accel_channels[] = {
CROS_EC_ACCEL_LEGACY_CHAN(X),
CROS_EC_ACCEL_LEGACY_CHAN(Y),
CROS_EC_ACCEL_LEGACY_CHAN(Z),
IIO_CHAN_SOFT_TIMESTAMP(MAX_AXIS)
};
static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
struct iio_dev *indio_dev;
struct cros_ec_accel_legacy_state *state;
int ret, i;
if (!ec || !ec->ec_dev) {
dev_warn(&pdev->dev, "No EC device found.\n");
return -EINVAL;
}
if (!ec->ec_dev->cmd_readmem) {
dev_warn(&pdev->dev, "EC does not support direct reads.\n");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
state = iio_priv(indio_dev);
state->ec = ec->ec_dev;
state->sensor_num = sensor_platform->sensor_num;
indio_dev->dev.parent = dev;
indio_dev->name = pdev->name;
indio_dev->channels = ec_accel_channels;
/*
* Present the channel using HTML5 standard:
* need to invert X and Y and invert some lid axis.
*/
for (i = X ; i < MAX_AXIS; i++) {
switch (i) {
case X:
ec_accel_channels[X].scan_index = Y;
case Y:
ec_accel_channels[Y].scan_index = X;
case Z:
ec_accel_channels[Z].scan_index = Z;
}
if (state->sensor_num == MOTIONSENSE_LOC_LID && i != Y)
state->sign[i] = -1;
else
state->sign[i] = 1;
}
indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &cros_ec_accel_legacy_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
cros_ec_accel_legacy_capture,
NULL);
if (ret)
return ret;
return devm_iio_device_register(dev, indio_dev);
}
static struct platform_driver cros_ec_accel_platform_driver = {
.driver = {
.name = DRV_NAME,
},
.probe = cros_ec_accel_legacy_probe,
};
module_platform_driver(cros_ec_accel_platform_driver);
MODULE_DESCRIPTION("ChromeOS EC legacy accelerometer driver");
MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
......@@ -34,6 +34,13 @@
#define KXCJK1013_DRV_NAME "kxcjk1013"
#define KXCJK1013_IRQ_NAME "kxcjk1013_event"
#define KXTF9_REG_HP_XOUT_L 0x00
#define KXTF9_REG_HP_XOUT_H 0x01
#define KXTF9_REG_HP_YOUT_L 0x02
#define KXTF9_REG_HP_YOUT_H 0x03
#define KXTF9_REG_HP_ZOUT_L 0x04
#define KXTF9_REG_HP_ZOUT_H 0x05
#define KXCJK1013_REG_XOUT_L 0x06
/*
* From low byte X axis register, all the other addresses of Y and Z can be
......@@ -48,17 +55,33 @@
#define KXCJK1013_REG_DCST_RESP 0x0C
#define KXCJK1013_REG_WHO_AM_I 0x0F
#define KXCJK1013_REG_INT_SRC1 0x16
#define KXTF9_REG_TILT_POS_CUR 0x10
#define KXTF9_REG_TILT_POS_PREV 0x11
#define KXTF9_REG_INT_SRC1 0x15
#define KXCJK1013_REG_INT_SRC1 0x16 /* compatible, but called INT_SRC2 in KXTF9 ds */
#define KXCJK1013_REG_INT_SRC2 0x17
#define KXCJK1013_REG_STATUS_REG 0x18
#define KXCJK1013_REG_INT_REL 0x1A
#define KXCJK1013_REG_CTRL1 0x1B
#define KXCJK1013_REG_CTRL2 0x1D
#define KXTF9_REG_CTRL2 0x1C
#define KXCJK1013_REG_CTRL2 0x1D /* mostly compatible, CTRL_REG3 in KTXF9 ds */
#define KXCJK1013_REG_INT_CTRL1 0x1E
#define KXCJK1013_REG_INT_CTRL2 0x1F
#define KXTF9_REG_INT_CTRL3 0x20
#define KXCJK1013_REG_DATA_CTRL 0x21
#define KXTF9_REG_TILT_TIMER 0x28
#define KXCJK1013_REG_WAKE_TIMER 0x29
#define KXTF9_REG_TDT_TIMER 0x2B
#define KXTF9_REG_TDT_THRESH_H 0x2C
#define KXTF9_REG_TDT_THRESH_L 0x2D
#define KXTF9_REG_TDT_TAP_TIMER 0x2E
#define KXTF9_REG_TDT_TOTAL_TIMER 0x2F
#define KXTF9_REG_TDT_LATENCY_TIMER 0x30
#define KXTF9_REG_TDT_WINDOW_TIMER 0x31
#define KXCJK1013_REG_SELF_TEST 0x3A
#define KXTF9_REG_WAKE_THRESH 0x5A
#define KXTF9_REG_TILT_ANGLE 0x5C
#define KXTF9_REG_HYST_SET 0x5F
#define KXCJK1013_REG_WAKE_THRES 0x6A
#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7)
......@@ -67,14 +90,33 @@
#define KXCJK1013_REG_CTRL1_BIT_GSEL1 BIT(4)
#define KXCJK1013_REG_CTRL1_BIT_GSEL0 BIT(3)
#define KXCJK1013_REG_CTRL1_BIT_WUFE BIT(1)
#define KXCJK1013_REG_INT_REG1_BIT_IEA BIT(4)
#define KXCJK1013_REG_INT_REG1_BIT_IEN BIT(5)
#define KXCJK1013_REG_INT_CTRL1_BIT_IEU BIT(2) /* KXTF9 */
#define KXCJK1013_REG_INT_CTRL1_BIT_IEL BIT(3)
#define KXCJK1013_REG_INT_CTRL1_BIT_IEA BIT(4)
#define KXCJK1013_REG_INT_CTRL1_BIT_IEN BIT(5)
#define KXTF9_REG_TILT_BIT_LEFT_EDGE BIT(5)
#define KXTF9_REG_TILT_BIT_RIGHT_EDGE BIT(4)
#define KXTF9_REG_TILT_BIT_LOWER_EDGE BIT(3)
#define KXTF9_REG_TILT_BIT_UPPER_EDGE BIT(2)
#define KXTF9_REG_TILT_BIT_FACE_DOWN BIT(1)
#define KXTF9_REG_TILT_BIT_FACE_UP BIT(0)
#define KXCJK1013_DATA_MASK_12_BIT 0x0FFF
#define KXCJK1013_MAX_STARTUP_TIME_US 100000
#define KXCJK1013_SLEEP_DELAY_MS 2000
#define KXCJK1013_REG_INT_SRC1_BIT_TPS BIT(0) /* KXTF9 */
#define KXCJK1013_REG_INT_SRC1_BIT_WUFS BIT(1)
#define KXCJK1013_REG_INT_SRC1_MASK_TDTS (BIT(2) | BIT(3)) /* KXTF9 */
#define KXCJK1013_REG_INT_SRC1_TAP_NONE 0
#define KXCJK1013_REG_INT_SRC1_TAP_SINGLE BIT(2)
#define KXCJK1013_REG_INT_SRC1_TAP_DOUBLE BIT(3)
#define KXCJK1013_REG_INT_SRC1_BIT_DRDY BIT(4)
/* KXCJK: INT_SOURCE2: motion detect, KXTF9: INT_SRC_REG1: tap detect */
#define KXCJK1013_REG_INT_SRC2_BIT_ZP BIT(0)
#define KXCJK1013_REG_INT_SRC2_BIT_ZN BIT(1)
#define KXCJK1013_REG_INT_SRC2_BIT_YP BIT(2)
......@@ -88,6 +130,7 @@ enum kx_chipset {
KXCJK1013,
KXCJ91008,
KXTJ21009,
KXTF9,
KX_MAX_CHIPS /* this must be last */
};
......@@ -128,15 +171,42 @@ enum kxcjk1013_range {
KXCJK1013_RANGE_8G,
};
static const struct {
struct kx_odr_map {
int val;
int val2;
int odr_bits;
} samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09},
{3, 125000, 0x0A}, {6, 250000, 0x0B}, {12, 500000, 0},
{25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03},
{200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06},
{1600, 0, 0x07} };
int wuf_bits;
};
static const struct kx_odr_map samp_freq_table[] = {
{ 0, 781000, 0x08, 0x00 },
{ 1, 563000, 0x09, 0x01 },
{ 3, 125000, 0x0A, 0x02 },
{ 6, 250000, 0x0B, 0x03 },
{ 12, 500000, 0x00, 0x04 },
{ 25, 0, 0x01, 0x05 },
{ 50, 0, 0x02, 0x06 },
{ 100, 0, 0x03, 0x06 },
{ 200, 0, 0x04, 0x06 },
{ 400, 0, 0x05, 0x06 },
{ 800, 0, 0x06, 0x06 },
{ 1600, 0, 0x07, 0x06 },
};
static const char *const kxcjk1013_samp_freq_avail =
"0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600";
static const struct kx_odr_map kxtf9_samp_freq_table[] = {
{ 25, 0, 0x01, 0x00 },
{ 50, 0, 0x02, 0x01 },
{ 100, 0, 0x03, 0x01 },
{ 200, 0, 0x04, 0x01 },
{ 400, 0, 0x05, 0x01 },
{ 800, 0, 0x06, 0x01 },
};
static const char *const kxtf9_samp_freq_avail =
"25 50 100 200 400 800";
/* Refer to section 4 of the specification */
static const struct {
......@@ -188,6 +258,15 @@ static const struct {
{0x06, 3000},
{0x07, 2000},
},
/* KXTF9 */
{
{0x01, 81000},
{0x02, 41000},
{0x03, 21000},
{0x04, 11000},
{0x05, 5100},
{0x06, 2700},
},
};
static const struct {
......@@ -198,23 +277,6 @@ static const struct {
{19163, 1, 0},
{38326, 0, 1} };
static const struct {
int val;
int val2;
int odr_bits;
} wake_odr_data_rate_table[] = { {0, 781000, 0x00},
{1, 563000, 0x01},
{3, 125000, 0x02},
{6, 250000, 0x03},
{12, 500000, 0x04},
{25, 0, 0x05},
{50, 0, 0x06},
{100, 0, 0x06},
{200, 0, 0x06},
{400, 0, 0x06},
{800, 0, 0x06},
{1600, 0, 0x06} };
static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
enum kxcjk1013_mode mode)
{
......@@ -341,9 +403,9 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
}
if (data->active_high_intr)
ret |= KXCJK1013_REG_INT_REG1_BIT_IEA;
ret |= KXCJK1013_REG_INT_CTRL1_BIT_IEA;
else
ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEA;
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEA;
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
ret);
......@@ -401,7 +463,7 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
{
int ret;
int waketh_reg, ret;
ret = i2c_smbus_write_byte_data(data->client,
KXCJK1013_REG_WAKE_TIMER,
......@@ -412,8 +474,9 @@ static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
return ret;
}
ret = i2c_smbus_write_byte_data(data->client,
KXCJK1013_REG_WAKE_THRES,
waketh_reg = data->chipset == KXTF9 ?
KXTF9_REG_WAKE_THRESH : KXCJK1013_REG_WAKE_THRES;
ret = i2c_smbus_write_byte_data(data->client, waketh_reg,
data->wake_thres);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_wake_thres\n");
......@@ -449,9 +512,9 @@ static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
}
if (status)
ret |= KXCJK1013_REG_INT_REG1_BIT_IEN;
ret |= KXCJK1013_REG_INT_CTRL1_BIT_IEN;
else
ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN;
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
ret);
......@@ -509,9 +572,9 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
}
if (status)
ret |= KXCJK1013_REG_INT_REG1_BIT_IEN;
ret |= KXCJK1013_REG_INT_CTRL1_BIT_IEN;
else
ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN;
ret &= ~KXCJK1013_REG_INT_CTRL1_BIT_IEN;
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
ret);
......@@ -547,28 +610,30 @@ static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
return 0;
}
static int kxcjk1013_convert_freq_to_bit(int val, int val2)
static const struct kx_odr_map *kxcjk1013_find_odr_value(
const struct kx_odr_map *map, size_t map_size, int val, int val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) {
if (samp_freq_table[i].val == val &&
samp_freq_table[i].val2 == val2) {
return samp_freq_table[i].odr_bits;
}
for (i = 0; i < map_size; ++i) {
if (map[i].val == val && map[i].val2 == val2)
return &map[i];
}
return -EINVAL;
return ERR_PTR(-EINVAL);
}
static int kxcjk1013_convert_wake_odr_to_bit(int val, int val2)
static int kxcjk1013_convert_odr_value(const struct kx_odr_map *map,
size_t map_size, int odr_bits,
int *val, int *val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(wake_odr_data_rate_table); ++i) {
if (wake_odr_data_rate_table[i].val == val &&
wake_odr_data_rate_table[i].val2 == val2) {
return wake_odr_data_rate_table[i].odr_bits;
for (i = 0; i < map_size; ++i) {
if (map[i].odr_bits == odr_bits) {
*val = map[i].val;
*val2 = map[i].val2;
return IIO_VAL_INT_PLUS_MICRO;
}
}
......@@ -578,16 +643,24 @@ static int kxcjk1013_convert_wake_odr_to_bit(int val, int val2)
static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
{
int ret;
int odr_bits;
enum kxcjk1013_mode store_mode;
const struct kx_odr_map *odr_setting;
ret = kxcjk1013_get_mode(data, &store_mode);
if (ret < 0)
return ret;
odr_bits = kxcjk1013_convert_freq_to_bit(val, val2);
if (odr_bits < 0)
return odr_bits;
if (data->chipset == KXTF9)
odr_setting = kxcjk1013_find_odr_value(kxtf9_samp_freq_table,
ARRAY_SIZE(kxtf9_samp_freq_table),
val, val2);
else
odr_setting = kxcjk1013_find_odr_value(samp_freq_table,
ARRAY_SIZE(samp_freq_table),
val, val2);
if (IS_ERR(odr_setting))
return PTR_ERR(odr_setting);
/* To change ODR, the chip must be set to STANDBY as per spec */
ret = kxcjk1013_set_mode(data, STANDBY);
......@@ -595,20 +668,16 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
return ret;
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL,
odr_bits);
odr_setting->odr_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing data_ctrl\n");
return ret;
}
data->odr_bits = odr_bits;
odr_bits = kxcjk1013_convert_wake_odr_to_bit(val, val2);
if (odr_bits < 0)
return odr_bits;
data->odr_bits = odr_setting->odr_bits;
ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2,
odr_bits);
odr_setting->wuf_bits);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
return ret;
......@@ -625,17 +694,14 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) {
if (samp_freq_table[i].odr_bits == data->odr_bits) {
*val = samp_freq_table[i].val;
*val2 = samp_freq_table[i].val2;
return IIO_VAL_INT_PLUS_MICRO;
}
}
return -EINVAL;
if (data->chipset == KXTF9)
return kxcjk1013_convert_odr_value(kxtf9_samp_freq_table,
ARRAY_SIZE(kxtf9_samp_freq_table),
data->odr_bits, val, val2);
else
return kxcjk1013_convert_odr_value(samp_freq_table,
ARRAY_SIZE(samp_freq_table),
data->odr_bits, val, val2);
}
static int kxcjk1013_get_acc_reg(struct kxcjk1013_data *data, int axis)
......@@ -886,13 +952,29 @@ static int kxcjk1013_buffer_postdisable(struct iio_dev *indio_dev)
return kxcjk1013_set_power_state(data, false);
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600");
static ssize_t kxcjk1013_get_samp_freq_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct kxcjk1013_data *data = iio_priv(indio_dev);
const char *str;
if (data->chipset == KXTF9)
str = kxtf9_samp_freq_avail;
else
str = kxcjk1013_samp_freq_avail;
return sprintf(buf, "%s\n", str);
}
static IIO_DEVICE_ATTR(in_accel_sampling_frequency_available, S_IRUGO,
kxcjk1013_get_samp_freq_avail, NULL, 0);
static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019163 0.038326");
static struct attribute *kxcjk1013_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_sampling_frequency_available.dev_attr.attr,
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
......@@ -1037,6 +1119,72 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
.try_reenable = kxcjk1013_trig_try_reen,
};
static void kxcjk1013_report_motion_event(struct iio_dev *indio_dev)
{
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret = i2c_smbus_read_byte_data(data->client,
KXCJK1013_REG_INT_SRC2);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_src2\n");
return;
}
if (ret & KXCJK1013_REG_INT_SRC2_BIT_XN)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_X,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_XP)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_X,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_YN)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Y,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_YP)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Y,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZN)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Z,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZP)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Z,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
}
static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
......@@ -1049,66 +1197,17 @@ static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
goto ack_intr;
}
if (ret & 0x02) {
ret = i2c_smbus_read_byte_data(data->client,
KXCJK1013_REG_INT_SRC2);
if (ret < 0) {
dev_err(&data->client->dev,
"Error reading reg_int_src2\n");
goto ack_intr;
}
if (ret & KXCJK1013_REG_INT_SRC2_BIT_XN)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_X,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_XP)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_X,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_YN)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Y,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_YP)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Y,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZN)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Z,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING),
data->timestamp);
if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZP)
if (ret & KXCJK1013_REG_INT_SRC1_BIT_WUFS) {
if (data->chipset == KXTF9)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
IIO_MOD_Z,
IIO_MOD_X_AND_Y_AND_Z,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING),
data->timestamp);
else
kxcjk1013_report_motion_event(indio_dev);
}
ack_intr:
......@@ -1401,6 +1500,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcjk1013", KXCJK1013},
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
{"kxtf9", KXTF9},
{"SMO8500", KXCJ91008},
{}
};
......
......@@ -792,7 +792,7 @@ static int mma8452_get_event_regs(struct mma8452_data *data,
}
}
static int mma8452_read_thresh(struct iio_dev *indio_dev,
static int mma8452_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
......@@ -855,7 +855,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
}
}
static int mma8452_write_thresh(struct iio_dev *indio_dev,
static int mma8452_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
......@@ -1391,8 +1391,8 @@ static const struct iio_info mma8452_info = {
.read_raw = &mma8452_read_raw,
.write_raw = &mma8452_write_raw,
.event_attrs = &mma8452_event_attribute_group,
.read_event_value = &mma8452_read_thresh,
.write_event_value = &mma8452_write_thresh,
.read_event_value = &mma8452_read_event_value,
.write_event_value = &mma8452_write_event_value,
.read_event_config = &mma8452_read_event_config,
.write_event_config = &mma8452_write_event_config,
.debugfs_reg_access = &mma8452_reg_access_dbg,
......
......@@ -32,6 +32,8 @@ enum st_accel_type {
H3LIS331DL,
LIS331DL,
LIS3LV02DL,
LIS2DW12,
LIS3DHH,
ST_ACCEL_MAX,
};
......@@ -52,6 +54,8 @@ enum st_accel_type {
#define LIS2DH12_ACCEL_DEV_NAME "lis2dh12_accel"
#define LIS3L02DQ_ACCEL_DEV_NAME "lis3l02dq"
#define LNG2DM_ACCEL_DEV_NAME "lng2dm"
#define LIS2DW12_ACCEL_DEV_NAME "lis2dw12"
#define LIS3DHH_ACCEL_DEV_NAME "lis3dhh"
/**
* struct st_sensors_platform_data - default accel platform data
......
......@@ -159,12 +159,16 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x10,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x22,
.mask = 0x10,
},
.addr_ihl = 0x25,
.mask_ihl = 0x02,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
......@@ -229,14 +233,24 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x02,
.mask_int2 = 0x10,
.int1 = {
.addr = 0x22,
.mask = 0x02,
.addr_od = 0x22,
.mask_od = 0x40,
},
.int2 = {
.addr = 0x22,
.mask = 0x10,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
......@@ -313,12 +327,16 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x08,
},
.drdy_irq = {
.addr = 0x23,
.mask_int1 = 0x80,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x23,
.mask = 0x80,
},
.addr_ihl = 0x23,
.mask_ihl = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
.ig1 = {
.en_addr = 0x23,
.en_mask = 0x08,
......@@ -387,9 +405,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x01,
},
.drdy_irq = {
.addr = 0x21,
.mask_int1 = 0x04,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.int1 = {
.addr = 0x21,
.mask = 0x04,
},
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x21,
......@@ -444,14 +467,24 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x04,
.mask_int2 = 0x20,
.int1 = {
.addr = 0x22,
.mask = 0x04,
.addr_od = 0x22,
.mask_od = 0x40,
},
.int2 = {
.addr = 0x22,
.mask = 0x20,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x21,
......@@ -513,9 +546,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x02,
.mask_int2 = 0x10,
.int1 = {
.addr = 0x22,
.mask = 0x02,
},
.int2 = {
.addr = 0x22,
.mask = 0x10,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
},
......@@ -567,9 +605,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.bdu = {
},
.drdy_irq = {
.addr = 0x21,
.mask_int1 = 0x04,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.int1 = {
.addr = 0x21,
.mask = 0x04,
},
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x21,
......@@ -635,12 +678,16 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x10,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x22,
.mask = 0x10,
},
.addr_ihl = 0x25,
.mask_ihl = 0x02,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
......@@ -649,6 +696,139 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = true,
.bootime = 2,
},
{
.wai = 0x44,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS2DW12_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = 0x20,
.mask = 0xf0,
.odr_avl = {
{ .hz = 1, .value = 0x01, },
{ .hz = 12, .value = 0x02, },
{ .hz = 25, .value = 0x03, },
{ .hz = 50, .value = 0x04, },
{ .hz = 100, .value = 0x05, },
{ .hz = 200, .value = 0x06, },
},
},
.pw = {
.addr = 0x20,
.mask = 0xf0,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.fs = {
.addr = 0x25,
.mask = 0x30,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = 0x00,
.gain = IIO_G_TO_M_S_2(976),
},
[1] = {
.num = ST_ACCEL_FS_AVL_4G,
.value = 0x01,
.gain = IIO_G_TO_M_S_2(1952),
},
[2] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = 0x02,
.gain = IIO_G_TO_M_S_2(3904),
},
[3] = {
.num = ST_ACCEL_FS_AVL_16G,
.value = 0x03,
.gain = IIO_G_TO_M_S_2(7808),
},
},
},
.bdu = {
.addr = 0x21,
.mask = 0x08,
},
.drdy_irq = {
.int1 = {
.addr = 0x23,
.mask = 0x01,
.addr_od = 0x22,
.mask_od = 0x20,
},
.int2 = {
.addr = 0x24,
.mask = 0x01,
.addr_od = 0x22,
.mask_od = 0x20,
},
.addr_ihl = 0x22,
.mask_ihl = 0x08,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x01,
},
},
.sim = {
.addr = 0x21,
.value = BIT(0),
},
.multi_read_bit = false,
.bootime = 2,
},
{
.wai = 0x11,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3DHH_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
/* just ODR = 1100Hz available */
.odr_avl = {
{ .hz = 1100, .value = 0x00, },
},
},
.pw = {
.addr = 0x20,
.mask = 0x80,
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.fs = {
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.gain = IIO_G_TO_M_S_2(76),
},
},
},
.bdu = {
.addr = 0x20,
.mask = 0x01,
},
.drdy_irq = {
.int1 = {
.addr = 0x21,
.mask = 0x80,
.addr_od = 0x23,
.mask_od = 0x04,
},
.int2 = {
.addr = 0x22,
.mask = 0x80,
.addr_od = 0x23,
.mask_od = 0x08,
},
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.multi_read_bit = false,
.bootime = 2,
},
};
static int st_accel_read_raw(struct iio_dev *indio_dev,
......
......@@ -94,6 +94,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lng2dm-accel",
.data = LNG2DM_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2dw12",
.data = LIS2DW12_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -129,6 +133,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ H3LIS331DL_ACCEL_DEV_NAME, H3LIS331DL },
{ LIS331DL_ACCEL_DEV_NAME, LIS331DL },
{ LIS3LV02DL_ACCEL_DEV_NAME, LIS3LV02DL },
{ LIS2DW12_ACCEL_DEV_NAME, LIS2DW12 },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
......
......@@ -82,6 +82,14 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis331dl-accel",
.data = LIS331DL_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2dw12",
.data = LIS2DW12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis3dhh",
.data = LIS3DHH_ACCEL_DEV_NAME,
},
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -133,6 +141,8 @@ static const struct spi_device_id st_accel_id_table[] = {
{ H3LIS331DL_ACCEL_DEV_NAME },
{ LIS331DL_ACCEL_DEV_NAME },
{ LIS3LV02DL_ACCEL_DEV_NAME },
{ LIS2DW12_ACCEL_DEV_NAME },
{ LIS3DHH_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
......
......@@ -475,12 +475,13 @@ config MAX9611
called max9611.
config MCP320X
tristate "Microchip Technology MCP3x01/02/04/08"
tristate "Microchip Technology MCP3x01/02/04/08 and MCP3550/1/3"
depends on SPI
help
Say yes here to build support for Microchip Technology's
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204,
MCP3208 or MCP3301 analog to digital converter.
MCP3208, MCP3301, MCP3550, MCP3551 and MCP3553 analog to digital
converters.
This driver can also be built as a module. If so, the module will be
called mcp320x.
......@@ -593,7 +594,7 @@ config QCOM_SPMI_VADC
config RCAR_GYRO_ADC
tristate "Renesas R-Car GyroADC driver"
depends on ARCH_RCAR_GEN2 || (ARM && COMPILE_TEST)
depends on ARCH_RCAR_GEN2 || COMPILE_TEST
help
Say yes here to build support for the GyroADC found in Renesas
R-Car Gen2 SoCs. This block is a simple SPI offload engine for
......
......@@ -123,7 +123,7 @@ struct ina2xx_chip_info {
struct task_struct *task;
const struct ina2xx_config *config;
struct mutex state_lock;
unsigned int shunt_resistor;
unsigned int shunt_resistor_uohm;
int avg;
int int_time_vbus; /* Bus voltage integration time uS */
int int_time_vshunt; /* Shunt voltage integration time uS */
......@@ -436,7 +436,7 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
/*
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet). We hardcode a Current_LSB
* of 1.0 x10-6. The only remaining parameter is RShunt.
* of 1.0 x10-3. The only remaining parameter is RShunt.
* There is no need to expose the CALIBRATION register
* to the user for now. But we need to reset this register
* if the user updates RShunt after driver init, e.g upon
......@@ -445,7 +445,7 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
static int ina2xx_set_calibration(struct ina2xx_chip_info *chip)
{
u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
chip->shunt_resistor);
chip->shunt_resistor_uohm);
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
}
......@@ -455,7 +455,7 @@ static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
if (val <= 0 || val > chip->config->calibration_factor)
return -EINVAL;
chip->shunt_resistor = val;
chip->shunt_resistor_uohm = val;
return 0;
}
......@@ -465,8 +465,9 @@ static ssize_t ina2xx_shunt_resistor_show(struct device *dev,
char *buf)
{
struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
int vals[2] = { chip->shunt_resistor_uohm, 1000000 };
return sprintf(buf, "%d\n", chip->shunt_resistor);
return iio_format_value(buf, IIO_VAL_FRACTIONAL, 1, vals);
}
static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
......@@ -474,14 +475,13 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
const char *buf, size_t len)
{
struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
unsigned long val;
int ret;
int val, val_fract, ret;
ret = kstrtoul((const char *) buf, 10, &val);
ret = iio_str_to_fixpoint(buf, 100000, &val, &val_fract);
if (ret)
return ret;
ret = set_shunt_resistor(chip, val);
ret = set_shunt_resistor(chip, val * 1000000 + val_fract);
if (ret)
return ret;
......
......@@ -19,6 +19,11 @@
* ------------
* 13 bit converter
* MCP3301
* ------------
* 22 bit converter
* MCP3550
* MCP3551
* MCP3553
*
* Datasheet can be found here:
* http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf mcp3001
......@@ -28,6 +33,7 @@
* http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202
* http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08
* http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301
* http://ww1.microchip.com/downloads/en/DeviceDoc/21950D.pdf mcp3550/1/3
*
* 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
......@@ -51,12 +57,17 @@ enum {
mcp3204,
mcp3208,
mcp3301,
mcp3550_50,
mcp3550_60,
mcp3551,
mcp3553,
};
struct mcp320x_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int resolution;
unsigned int conv_time; /* usec */
};
/**
......@@ -64,6 +75,8 @@ struct mcp320x_chip_info {
* @spi: SPI slave (parent of the IIO device)
* @msg: SPI message to select a channel and receive a value from the ADC
* @transfer: SPI transfers used by @msg
* @start_conv_msg: SPI message to start a conversion by briefly asserting CS
* @start_conv_transfer: SPI transfer used by @start_conv_msg
* @reg: regulator generating Vref
* @lock: protects read sequences
* @chip_info: ADC properties
......@@ -74,13 +87,15 @@ struct mcp320x {
struct spi_device *spi;
struct spi_message msg;
struct spi_transfer transfer[2];
struct spi_message start_conv_msg;
struct spi_transfer start_conv_transfer;
struct regulator *reg;
struct mutex lock;
const struct mcp320x_chip_info *chip_info;
u8 tx_buf ____cacheline_aligned;
u8 rx_buf[2];
u8 rx_buf[4];
};
static int mcp320x_channel_to_tx_data(int device_index,
......@@ -109,6 +124,15 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
{
int ret;
if (adc->chip_info->conv_time) {
ret = spi_sync(adc->spi, &adc->start_conv_msg);
if (ret < 0)
return ret;
usleep_range(adc->chip_info->conv_time,
adc->chip_info->conv_time + 100);
}
memset(&adc->rx_buf, 0, sizeof(adc->rx_buf));
if (adc->chip_info->num_channels > 1)
adc->tx_buf = mcp320x_channel_to_tx_data(device_index, channel,
......@@ -139,6 +163,31 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
*val = sign_extend32((adc->rx_buf[0] & 0x1f) << 8
| adc->rx_buf[1], 12);
return 0;
case mcp3550_50:
case mcp3550_60:
case mcp3551:
case mcp3553: {
u32 raw = be32_to_cpup((u32 *)adc->rx_buf);
if (!(adc->spi->mode & SPI_CPOL))
raw <<= 1; /* strip Data Ready bit in SPI mode 0,0 */
/*
* If the input is within -vref and vref, bit 21 is the sign.
* Up to 12% overrange or underrange are allowed, in which case
* bit 23 is the sign and bit 0 to 21 is the value.
*/
raw >>= 8;
if (raw & BIT(22) && raw & BIT(23))
return -EIO; /* cannot have overrange AND underrange */
else if (raw & BIT(22))
raw &= ~BIT(22); /* overrange */
else if (raw & BIT(23) || raw & BIT(21))
raw |= GENMASK(31, 22); /* underrange or negative */
*val = (s32)raw;
return 0;
}
default:
return -EINVAL;
}
......@@ -297,6 +346,31 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 13
},
[mcp3550_50] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
/* 2% max deviation + 144 clock periods to exit shutdown */
.conv_time = 80000 * 1.02 + 144000 / 102.4,
},
[mcp3550_60] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
.conv_time = 66670 * 1.02 + 144000 / 122.88,
},
[mcp3551] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
.conv_time = 73100 * 1.02 + 144000 / 112.64,
},
[mcp3553] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
.conv_time = 16670 * 1.02 + 144000 / 122.88,
},
};
static int mcp320x_probe(struct spi_device *spi)
......@@ -304,7 +378,7 @@ static int mcp320x_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct mcp320x *adc;
const struct mcp320x_chip_info *chip_info;
int ret;
int ret, device_index;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
......@@ -320,7 +394,8 @@ static int mcp320x_probe(struct spi_device *spi)
indio_dev->info = &mcp320x_info;
spi_set_drvdata(spi, indio_dev);
chip_info = &mcp320x_chip_infos[spi_get_device_id(spi)->driver_data];
device_index = spi_get_device_id(spi)->driver_data;
chip_info = &mcp320x_chip_infos[device_index];
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = chip_info->num_channels;
......@@ -329,7 +404,8 @@ static int mcp320x_probe(struct spi_device *spi)
adc->transfer[0].tx_buf = &adc->tx_buf;
adc->transfer[0].len = sizeof(adc->tx_buf);
adc->transfer[1].rx_buf = adc->rx_buf;
adc->transfer[1].len = sizeof(adc->rx_buf);
adc->transfer[1].len = DIV_ROUND_UP(chip_info->resolution, 8);
if (chip_info->num_channels == 1)
/* single-channel converters are rx only (no MOSI pin) */
spi_message_init_with_transfers(&adc->msg,
......@@ -338,6 +414,32 @@ static int mcp320x_probe(struct spi_device *spi)
spi_message_init_with_transfers(&adc->msg, adc->transfer,
ARRAY_SIZE(adc->transfer));
switch (device_index) {
case mcp3550_50:
case mcp3550_60:
case mcp3551:
case mcp3553:
/* rx len increases from 24 to 25 bit in SPI mode 0,0 */
if (!(spi->mode & SPI_CPOL))
adc->transfer[1].len++;
/* conversions are started by asserting CS pin for 8 usec */
adc->start_conv_transfer.delay_usecs = 8;
spi_message_init_with_transfers(&adc->start_conv_msg,
&adc->start_conv_transfer, 1);
/*
* If CS was previously kept low (continuous conversion mode)
* and then changed to high, the chip is in shutdown.
* Sometimes it fails to wake from shutdown and clocks out
* only 0xffffff. The magic sequence of performing two
* conversions without delay between them resets the chip
* and ensures all subsequent conversions succeed.
*/
mcp320x_adc_conversion(adc, 0, 1, device_index, &ret);
mcp320x_adc_conversion(adc, 0, 1, device_index, &ret);
}
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
......@@ -392,6 +494,10 @@ static const struct of_device_id mcp320x_dt_ids[] = {
{ .compatible = "microchip,mcp3204" },
{ .compatible = "microchip,mcp3208" },
{ .compatible = "microchip,mcp3301" },
{ .compatible = "microchip,mcp3550-50" },
{ .compatible = "microchip,mcp3550-60" },
{ .compatible = "microchip,mcp3551" },
{ .compatible = "microchip,mcp3553" },
{ }
};
MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
......@@ -407,6 +513,10 @@ static const struct spi_device_id mcp320x_id[] = {
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
{ "mcp3301", mcp3301 },
{ "mcp3550-50", mcp3550_50 },
{ "mcp3550-60", mcp3550_60 },
{ "mcp3551", mcp3551 },
{ "mcp3553", mcp3553 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);
......@@ -423,5 +533,5 @@ static struct spi_driver mcp320x_driver = {
module_spi_driver(mcp320x_driver);
MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08");
MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08 and MCP3550/1/3");
MODULE_LICENSE("GPL v2");
......@@ -348,7 +348,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
continue;
}
childmode = (unsigned int)of_id->data;
childmode = (uintptr_t)of_id->data;
switch (childmode) {
case RCAR_GYROADC_MODE_SELECT_1_MB88101A:
sample_width = 12;
......@@ -487,8 +487,6 @@ static int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev)
static int rcar_gyroadc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(rcar_gyroadc_match, &pdev->dev);
struct device *dev = &pdev->dev;
struct rcar_gyroadc *priv;
struct iio_dev *indio_dev;
......@@ -525,7 +523,8 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
if (ret)
return ret;
priv->model = (enum rcar_gyroadc_model)of_id->data;
priv->model = (enum rcar_gyroadc_model)
of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, indio_dev);
......
......@@ -528,17 +528,10 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
return ret;
}
if (!IS_ENABLED(CONFIG_THERMAL_OF))
return 0;
if (IS_ENABLED(CONFIG_THERMAL_OF))
info->sensor_device = &pdev->dev;
info->sensor_device = &pdev->dev;
info->tzd = thermal_zone_of_sensor_register(info->sensor_device, 0,
info, &sun4i_ts_tz_ops);
if (IS_ERR(info->tzd))
dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
return PTR_ERR_OR_ZERO(info->tzd);
return 0;
}
static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
......@@ -585,15 +578,6 @@ static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
* return the temperature.
*/
info->sensor_device = pdev->dev.parent;
info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
0, info,
&sun4i_ts_tz_ops);
if (IS_ERR(info->tzd)) {
dev_err(&pdev->dev,
"could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
return PTR_ERR(info->tzd);
}
} else {
indio_dev->num_channels =
ARRAY_SIZE(sun4i_gpadc_channels_no_temp);
......@@ -663,6 +647,22 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_enable(&pdev->dev);
if (IS_ENABLED(CONFIG_THERMAL_OF)) {
info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
0, info,
&sun4i_ts_tz_ops);
/*
* Do not fail driver probing when failing to register in
* thermal because no thermal DT node is found.
*/
if (IS_ERR(info->tzd) && PTR_ERR(info->tzd) != -ENODEV) {
dev_err(&pdev->dev,
"could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
return PTR_ERR(info->tzd);
}
}
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "could not register the device\n");
......
......@@ -179,6 +179,10 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
int ret;
atomic_set(&st->user_requested_state, state);
if (atomic_add_unless(&st->runtime_pm_enable, 1, 1))
pm_runtime_enable(&st->pdev->dev);
if (state)
ret = pm_runtime_get_sync(&st->pdev->dev);
else {
......@@ -221,7 +225,8 @@ static void hid_sensor_set_power_work(struct work_struct *work)
if (attrb->latency_ms > 0)
hid_sensor_set_report_latency(attrb, attrb->latency_ms);
_hid_sensor_power_state(attrb, true);
if (atomic_read(&attrb->user_requested_state))
_hid_sensor_power_state(attrb, true);
}
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
......@@ -232,7 +237,9 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
{
pm_runtime_disable(&attrb->pdev->dev);
if (atomic_read(&attrb->runtime_pm_enable))
pm_runtime_disable(&attrb->pdev->dev);
pm_runtime_set_suspended(&attrb->pdev->dev);
pm_runtime_put_noidle(&attrb->pdev->dev);
......@@ -282,7 +289,6 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
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 */
pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
3000);
......
......@@ -93,6 +93,9 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
struct st_sensor_odr_avl odr_out = {0, 0};
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (!sdata->sensor_settings->odr.addr)
return 0;
err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
if (err < 0)
goto st_sensors_match_odr_error;
......@@ -221,11 +224,14 @@ EXPORT_SYMBOL(st_sensors_set_enable);
int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
int err = 0;
return st_sensors_write_data_with_mask(indio_dev,
if (sdata->sensor_settings->enable_axis.addr)
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->enable_axis.addr,
sdata->sensor_settings->enable_axis.mask,
axis_enable);
return err;
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
......@@ -283,7 +289,8 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
struct st_sensor_data *sdata = iio_priv(indio_dev);
/* Sensor does not support interrupts */
if (sdata->sensor_settings->drdy_irq.addr == 0) {
if (!sdata->sensor_settings->drdy_irq.int1.addr &&
!sdata->sensor_settings->drdy_irq.int2.addr) {
if (pdata->drdy_int_pin)
dev_info(&indio_dev->dev,
"DRDY on pin INT%d specified, but sensor "
......@@ -294,7 +301,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
switch (pdata->drdy_int_pin) {
case 1:
if (sdata->sensor_settings->drdy_irq.mask_int1 == 0) {
if (!sdata->sensor_settings->drdy_irq.int1.mask) {
dev_err(&indio_dev->dev,
"DRDY on INT1 not available.\n");
return -EINVAL;
......@@ -302,7 +309,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
sdata->drdy_int_pin = 1;
break;
case 2:
if (sdata->sensor_settings->drdy_irq.mask_int2 == 0) {
if (!sdata->sensor_settings->drdy_irq.int2.mask) {
dev_err(&indio_dev->dev,
"DRDY on INT2 not available.\n");
return -EINVAL;
......@@ -315,7 +322,8 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
}
if (pdata->open_drain) {
if (!sdata->sensor_settings->drdy_irq.addr_od)
if (!sdata->sensor_settings->drdy_irq.int1.addr_od &&
!sdata->sensor_settings->drdy_irq.int2.addr_od)
dev_err(&indio_dev->dev,
"open drain requested but unsupported.\n");
else
......@@ -442,11 +450,21 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
}
if (sdata->int_pin_open_drain) {
u8 addr, mask;
if (sdata->drdy_int_pin == 1) {
addr = sdata->sensor_settings->drdy_irq.int1.addr_od;
mask = sdata->sensor_settings->drdy_irq.int1.mask_od;
} else {
addr = sdata->sensor_settings->drdy_irq.int2.addr_od;
mask = sdata->sensor_settings->drdy_irq.int2.mask_od;
}
dev_info(&indio_dev->dev,
"set interrupt line to open drain mode\n");
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->drdy_irq.addr_od,
sdata->sensor_settings->drdy_irq.mask_od, 1);
"set interrupt line to open drain mode on pin %d\n",
sdata->drdy_int_pin);
err = st_sensors_write_data_with_mask(indio_dev, addr,
mask, 1);
if (err < 0)
return err;
}
......@@ -460,17 +478,18 @@ EXPORT_SYMBOL(st_sensors_init_sensor);
int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
{
int err;
u8 drdy_mask;
u8 drdy_addr, drdy_mask;
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (!sdata->sensor_settings->drdy_irq.addr) {
if (!sdata->sensor_settings->drdy_irq.int1.addr &&
!sdata->sensor_settings->drdy_irq.int2.addr) {
/*
* there are some devices (e.g. LIS3MDL) where drdy line is
* routed to a given pin and it is not possible to select a
* different one. Take into account irq status register
* to understand if irq trigger can be properly supported
*/
if (sdata->sensor_settings->drdy_irq.addr_stat_drdy)
if (sdata->sensor_settings->drdy_irq.stat_drdy.addr)
sdata->hw_irq_trigger = enable;
return 0;
}
......@@ -485,18 +504,20 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
goto st_accel_set_dataready_irq_error;
}
if (sdata->drdy_int_pin == 1)
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int1;
else
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
if (sdata->drdy_int_pin == 1) {
drdy_addr = sdata->sensor_settings->drdy_irq.int1.addr;
drdy_mask = sdata->sensor_settings->drdy_irq.int1.mask;
} else {
drdy_addr = sdata->sensor_settings->drdy_irq.int2.addr;
drdy_mask = sdata->sensor_settings->drdy_irq.int2.mask;
}
/* Flag to the poll function that the hardware trigger is in use */
sdata->hw_irq_trigger = enable;
/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->drdy_irq.addr,
drdy_mask, (int)enable);
err = st_sensors_write_data_with_mask(indio_dev, drdy_addr,
drdy_mask, (int)enable);
st_accel_set_dataready_irq_error:
return err;
......
......@@ -31,7 +31,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
int ret;
/* How would I know if I can't check it? */
if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy)
if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr)
return -EINVAL;
/* No scan mask, no interrupt */
......@@ -39,23 +39,15 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
return 0;
ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
sdata->sensor_settings->drdy_irq.stat_drdy.addr,
&status);
if (ret < 0) {
dev_err(sdata->dev,
"error checking samples available\n");
return ret;
}
/*
* the lower bits of .active_scan_mask[0] is directly mapped
* to the channels on the sensor: either bit 0 for
* one-dimensional sensors, or e.g. x,y,z for accelerometers,
* gyroscopes or magnetometers. No sensor use more than 3
* channels, so cut the other status bits here.
*/
status &= 0x07;
if (status & (u8)indio_dev->active_scan_mask[0])
if (status & sdata->sensor_settings->drdy_irq.stat_drdy.mask)
return 1;
return 0;
......@@ -212,7 +204,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
* it was "our" interrupt.
*/
if (sdata->int_pin_open_drain &&
sdata->sensor_settings->drdy_irq.addr_stat_drdy)
sdata->sensor_settings->drdy_irq.stat_drdy.addr)
irq_trig |= IRQF_SHARED;
err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
......
......@@ -222,6 +222,15 @@ config DPOT_DAC
To compile this driver as a module, choose M here: the module will be
called dpot-dac.
config DS4424
tristate "Maxim Integrated DS4422/DS4424 DAC driver"
depends on I2C
help
If you say yes here you get support for Maxim chips DS4422, DS4424.
This driver can also be built as a module. If so, the module
will be called ds4424.
config LPC18XX_DAC
tristate "NXP LPC18xx DAC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
......
......@@ -23,6 +23,7 @@ obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_AD8801) += ad8801.o
obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
obj-$(CONFIG_DS4424) += ds4424.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_LTC2632) += ltc2632.o
obj-$(CONFIG_M62332) += m62332.o
......
/*
* Maxim Integrated
* 7-bit, Multi-Channel Sink/Source Current DAC Driver
* Copyright (C) 2017 Maxim Integrated
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/iio/consumer.h>
#define DS4422_MAX_DAC_CHANNELS 2
#define DS4424_MAX_DAC_CHANNELS 4
#define DS4424_DAC_ADDR(chan) ((chan) + 0xf8)
#define DS4424_SOURCE_I 1
#define DS4424_SINK_I 0
#define DS4424_CHANNEL(chan) { \
.type = IIO_CURRENT, \
.indexed = 1, \
.output = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
/*
* DS4424 DAC control register 8 bits
* [7] 0: to sink; 1: to source
* [6:0] steps to sink/source
* bit[7] looks like a sign bit, but the value of the register is
* not a two's complement code considering the bit[6:0] is a absolute
* distance from the zero point.
*/
union ds4424_raw_data {
struct {
u8 dx:7;
u8 source_bit:1;
};
u8 bits;
};
enum ds4424_device_ids {
ID_DS4422,
ID_DS4424,
};
struct ds4424_data {
struct i2c_client *client;
struct mutex lock;
uint8_t save[DS4424_MAX_DAC_CHANNELS];
struct regulator *vcc_reg;
uint8_t raw[DS4424_MAX_DAC_CHANNELS];
};
static const struct iio_chan_spec ds4424_channels[] = {
DS4424_CHANNEL(0),
DS4424_CHANNEL(1),
DS4424_CHANNEL(2),
DS4424_CHANNEL(3),
};
static int ds4424_get_value(struct iio_dev *indio_dev,
int *val, int channel)
{
struct ds4424_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
if (ret < 0)
goto fail;
*val = ret;
fail:
mutex_unlock(&data->lock);
return ret;
}
static int ds4424_set_value(struct iio_dev *indio_dev,
int val, struct iio_chan_spec const *chan)
{
struct ds4424_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client,
DS4424_DAC_ADDR(chan->channel), val);
if (ret < 0)
goto fail;
data->raw[chan->channel] = val;
fail:
mutex_unlock(&data->lock);
return ret;
}
static int ds4424_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
union ds4424_raw_data raw;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = ds4424_get_value(indio_dev, val, chan->channel);
if (ret < 0) {
pr_err("%s : ds4424_get_value returned %d\n",
__func__, ret);
return ret;
}
raw.bits = *val;
*val = raw.dx;
if (raw.source_bit == DS4424_SINK_I)
*val = -*val;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int ds4424_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
union ds4424_raw_data raw;
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < S8_MIN || val > S8_MAX)
return -EINVAL;
if (val > 0) {
raw.source_bit = DS4424_SOURCE_I;
raw.dx = val;
} else {
raw.source_bit = DS4424_SINK_I;
raw.dx = -val;
}
return ds4424_set_value(indio_dev, raw.bits, chan);
default:
return -EINVAL;
}
}
static int ds4424_verify_chip(struct iio_dev *indio_dev)
{
int ret, val;
ret = ds4424_get_value(indio_dev, &val, DS4424_DAC_ADDR(0));
if (ret < 0)
dev_err(&indio_dev->dev,
"%s failed. ret: %d\n", __func__, ret);
return ret;
}
static int __maybe_unused ds4424_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ds4424_data *data = iio_priv(indio_dev);
int ret = 0;
int i;
for (i = 0; i < indio_dev->num_channels; i++) {
data->save[i] = data->raw[i];
ret = ds4424_set_value(indio_dev, 0,
&indio_dev->channels[i]);
if (ret < 0)
return ret;
}
return ret;
}
static int __maybe_unused ds4424_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ds4424_data *data = iio_priv(indio_dev);
int ret = 0;
int i;
for (i = 0; i < indio_dev->num_channels; i++) {
ret = ds4424_set_value(indio_dev, data->save[i],
&indio_dev->channels[i]);
if (ret < 0)
return ret;
}
return ret;
}
static SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
static const struct iio_info ds4424_info = {
.read_raw = ds4424_read_raw,
.write_raw = ds4424_write_raw,
};
static int ds4424_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ds4424_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&client->dev, "iio dev alloc failed.\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
indio_dev->name = id->name;
indio_dev->dev.of_node = client->dev.of_node;
indio_dev->dev.parent = &client->dev;
if (!client->dev.of_node) {
dev_err(&client->dev,
"Not found DT.\n");
return -ENODEV;
}
data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(data->vcc_reg)) {
dev_err(&client->dev,
"Failed to get vcc-supply regulator. err: %ld\n",
PTR_ERR(data->vcc_reg));
return PTR_ERR(data->vcc_reg);
}
mutex_init(&data->lock);
ret = regulator_enable(data->vcc_reg);
if (ret < 0) {
dev_err(&client->dev,
"Unable to enable the regulator.\n");
return ret;
}
usleep_range(1000, 1200);
ret = ds4424_verify_chip(indio_dev);
if (ret < 0)
goto fail;
switch (id->driver_data) {
case ID_DS4422:
indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS;
break;
case ID_DS4424:
indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS;
break;
default:
dev_err(&client->dev,
"ds4424: Invalid chip id.\n");
ret = -ENXIO;
goto fail;
}
indio_dev->channels = ds4424_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ds4424_info;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev,
"iio_device_register failed. ret: %d\n", ret);
goto fail;
}
return ret;
fail:
regulator_disable(data->vcc_reg);
return ret;
}
static int ds4424_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ds4424_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(data->vcc_reg);
return 0;
}
static const struct i2c_device_id ds4424_id[] = {
{ "ds4422", ID_DS4422 },
{ "ds4424", ID_DS4424 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds4424_id);
static const struct of_device_id ds4424_of_match[] = {
{ .compatible = "maxim,ds4422" },
{ .compatible = "maxim,ds4424" },
{ },
};
MODULE_DEVICE_TABLE(of, ds4424_of_match);
static struct i2c_driver ds4424_driver = {
.driver = {
.name = "ds4424",
.of_match_table = ds4424_of_match,
.pm = &ds4424_pm_ops,
},
.probe = ds4424_probe,
.remove = ds4424_remove,
.id_table = ds4424_id,
};
module_i2c_driver(ds4424_driver);
MODULE_DESCRIPTION("Maxim DS4424 DAC Driver");
MODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>");
MODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>");
MODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>");
MODULE_LICENSE("GPL v2");
......@@ -5,7 +5,7 @@ menu "IIO dummy driver"
depends on IIO
config IIO_DUMMY_EVGEN
select IRQ_WORK
select IRQ_SIM
tristate
config IIO_SIMPLE_DUMMY
......
......@@ -24,97 +24,46 @@
#include "iio_dummy_evgen.h"
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/irq_work.h>
#include <linux/irq_sim.h>
/* Fiddly bit of faking and irq without hardware */
#define IIO_EVENTGEN_NO 10
/**
* struct iio_dummy_handle_irq - helper struct to simulate interrupt generation
* @work: irq_work used to run handlers from hardirq context
* @irq: fake irq line number to trigger an interrupt
*/
struct iio_dummy_handle_irq {
struct irq_work work;
int irq;
};
/**
* struct iio_dummy_evgen - evgen state
* @chip: irq chip we are faking
* @base: base of irq range
* @enabled: mask of which irqs are enabled
* @inuse: mask of which irqs are connected
* @regs: irq regs we are faking
* @lock: protect the evgen state
* @handler: helper for a 'hardware-like' interrupt simulation
* @inuse: mask of which irqs are connected
* @irq_sim: interrupt simulator
* @base: base of irq range
*/
struct iio_dummy_eventgen {
struct irq_chip chip;
int base;
bool enabled[IIO_EVENTGEN_NO];
bool inuse[IIO_EVENTGEN_NO];
struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
struct mutex lock;
struct iio_dummy_handle_irq handler;
bool inuse[IIO_EVENTGEN_NO];
struct irq_sim irq_sim;
int base;
};
/* We can only ever have one instance of this 'device' */
static struct iio_dummy_eventgen *iio_evgen;
static const char *iio_evgen_name = "iio_dummy_evgen";
static void iio_dummy_event_irqmask(struct irq_data *d)
{
struct irq_chip *chip = irq_data_get_irq_chip(d);
struct iio_dummy_eventgen *evgen =
container_of(chip, struct iio_dummy_eventgen, chip);
evgen->enabled[d->irq - evgen->base] = false;
}
static void iio_dummy_event_irqunmask(struct irq_data *d)
{
struct irq_chip *chip = irq_data_get_irq_chip(d);
struct iio_dummy_eventgen *evgen =
container_of(chip, struct iio_dummy_eventgen, chip);
evgen->enabled[d->irq - evgen->base] = true;
}
static void iio_dummy_work_handler(struct irq_work *work)
{
struct iio_dummy_handle_irq *irq_handler;
irq_handler = container_of(work, struct iio_dummy_handle_irq, work);
handle_simple_irq(irq_to_desc(irq_handler->irq));
}
static int iio_dummy_evgen_create(void)
{
int ret, i;
int ret;
iio_evgen = kzalloc(sizeof(*iio_evgen), GFP_KERNEL);
if (!iio_evgen)
return -ENOMEM;
iio_evgen->base = irq_alloc_descs(-1, 0, IIO_EVENTGEN_NO, 0);
if (iio_evgen->base < 0) {
ret = iio_evgen->base;
ret = irq_sim_init(&iio_evgen->irq_sim, IIO_EVENTGEN_NO);
if (ret) {
kfree(iio_evgen);
return ret;
}
iio_evgen->chip.name = iio_evgen_name;
iio_evgen->chip.irq_mask = &iio_dummy_event_irqmask;
iio_evgen->chip.irq_unmask = &iio_dummy_event_irqunmask;
for (i = 0; i < IIO_EVENTGEN_NO; i++) {
irq_set_chip(iio_evgen->base + i, &iio_evgen->chip);
irq_set_handler(iio_evgen->base + i, &handle_simple_irq);
irq_modify_status(iio_evgen->base + i,
IRQ_NOREQUEST | IRQ_NOAUTOEN,
IRQ_NOPROBE);
}
init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
iio_evgen->base = irq_sim_irqnum(&iio_evgen->irq_sim, 0);
mutex_init(&iio_evgen->lock);
return 0;
}
......@@ -132,15 +81,17 @@ int iio_dummy_evgen_get_irq(void)
return -ENODEV;
mutex_lock(&iio_evgen->lock);
for (i = 0; i < IIO_EVENTGEN_NO; i++)
for (i = 0; i < IIO_EVENTGEN_NO; i++) {
if (!iio_evgen->inuse[i]) {
ret = iio_evgen->base + i;
ret = irq_sim_irqnum(&iio_evgen->irq_sim, i);
iio_evgen->inuse[i] = true;
break;
}
}
mutex_unlock(&iio_evgen->lock);
if (i == IIO_EVENTGEN_NO)
return -ENOMEM;
return ret;
}
EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
......@@ -167,7 +118,7 @@ EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
static void iio_dummy_evgen_free(void)
{
irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
irq_sim_fini(&iio_evgen->irq_sim);
kfree(iio_evgen);
}
......@@ -192,9 +143,7 @@ static ssize_t iio_evgen_poke(struct device *dev,
iio_evgen->regs[this_attr->address].reg_id = this_attr->address;
iio_evgen->regs[this_attr->address].reg_data = event;
iio_evgen->handler.irq = iio_evgen->base + this_attr->address;
if (iio_evgen->enabled[this_attr->address])
irq_work_queue(&iio_evgen->handler.work);
irq_sim_fire(&iio_evgen->irq_sim, this_attr->address);
return len;
}
......
......@@ -111,14 +111,23 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int2 = 0x08,
.int2 = {
.addr = 0x22,
.mask = 0x08,
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -181,14 +190,23 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int2 = 0x08,
.int2 = {
.addr = 0x22,
.mask = 0x08,
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -246,14 +264,23 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int2 = 0x08,
.int2 = {
.addr = 0x22,
.mask = 0x08,
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......
......@@ -29,8 +29,6 @@ enum st_lsm6dsx_hw_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
......@@ -52,10 +50,38 @@ struct st_lsm6dsx_reg {
u8 mask;
};
/**
* struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
* @fifo_th: FIFO threshold register info (addr + mask).
* @fifo_diff: FIFO diff status register info (addr + mask).
* @th_wl: FIFO threshold word length.
*/
struct st_lsm6dsx_fifo_ops {
struct {
u8 addr;
u16 mask;
} fifo_th;
struct {
u8 addr;
u16 mask;
} fifo_diff;
u8 th_wl;
};
/**
* struct st_lsm6dsx_settings - ST IMU sensor settings
* @wai: Sensor WhoAmI default value.
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id supported by the driver configuration.
* @decimator: List of decimator register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
*/
struct st_lsm6dsx_settings {
u8 wai;
u16 max_fifo_size;
enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
};
enum st_lsm6dsx_sensor_id {
......@@ -79,7 +105,6 @@ enum st_lsm6dsx_fifo_mode {
* @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.
*/
......@@ -94,7 +119,6 @@ struct st_lsm6dsx_sensor {
u16 watermark;
u8 sip;
u8 decimator;
u8 decimator_mask;
s64 delta_ts;
s64 ts;
......
......@@ -35,10 +35,6 @@
#include "st_lsm6dsx.h"
#define ST_LSM6DSX_REG_FIFO_THL_ADDR 0x06
#define ST_LSM6DSX_REG_FIFO_THH_ADDR 0x07
#define ST_LSM6DSX_FIFO_TH_MASK GENMASK(11, 0)
#define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR 0x08
#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12
#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5)
#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12
......@@ -46,8 +42,6 @@
#define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a
#define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0)
#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
#define ST_LSM6DSX_REG_FIFO_DIFFL_ADDR 0x3a
#define ST_LSM6DSX_FIFO_DIFF_MASK GENMASK(11, 0)
#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
......@@ -110,8 +104,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
sensor = iio_priv(hw->iio_devs[i]);
const struct st_lsm6dsx_reg *dec_reg;
sensor = iio_priv(hw->iio_devs[i]);
/* update fifo decimators and sample in pattern */
if (hw->enable_mask & BIT(sensor->id)) {
sensor->sip = sensor->odr / min_odr;
......@@ -123,12 +118,13 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
data = 0;
}
err = st_lsm6dsx_write_with_mask(hw,
ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR,
sensor->decimator_mask, data);
if (err < 0)
return err;
dec_reg = &hw->settings->decimator[sensor->id];
if (dec_reg->addr) {
err = st_lsm6dsx_write_with_mask(hw, dec_reg->addr,
dec_reg->mask, data);
if (err < 0)
return err;
}
sip += sensor->sip;
}
hw->sip = sip;
......@@ -139,23 +135,10 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode)
{
u8 data;
int err;
switch (fifo_mode) {
case ST_LSM6DSX_FIFO_BYPASS:
data = fifo_mode;
break;
case ST_LSM6DSX_FIFO_CONT:
data = (ST_LSM6DSX_MAX_FIFO_ODR_VAL <<
__ffs(ST_LSM6DSX_FIFO_ODR_MASK)) | fifo_mode;
break;
default:
return -EINVAL;
}
err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
sizeof(data), &data);
err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_MODE_MASK, fifo_mode);
if (err < 0)
return err;
......@@ -164,9 +147,20 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
return 0;
}
static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
bool enable)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
u8 data;
data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
return st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_ODR_MASK, data);
}
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
{
u16 fifo_watermark = ~0, cur_watermark, sip = 0;
u16 fifo_watermark = ~0, cur_watermark, sip = 0, fifo_th_mask;
struct st_lsm6dsx_hw *hw = sensor->hw;
struct st_lsm6dsx_sensor *cur_sensor;
__le16 wdata;
......@@ -191,20 +185,21 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
fifo_watermark = max_t(u16, fifo_watermark, sip);
fifo_watermark = (fifo_watermark / sip) * sip;
fifo_watermark = fifo_watermark * ST_LSM6DSX_SAMPLE_DEPTH;
fifo_watermark = fifo_watermark * hw->settings->fifo_ops.th_wl;
mutex_lock(&hw->lock);
err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_THH_ADDR,
err = hw->tf->read(hw->dev, hw->settings->fifo_ops.fifo_th.addr + 1,
sizeof(data), &data);
if (err < 0)
goto out;
fifo_watermark = ((data << 8) & ~ST_LSM6DSX_FIFO_TH_MASK) |
(fifo_watermark & ST_LSM6DSX_FIFO_TH_MASK);
fifo_th_mask = hw->settings->fifo_ops.fifo_th.mask;
fifo_watermark = ((data << 8) & ~fifo_th_mask) |
(fifo_watermark & fifo_th_mask);
wdata = cpu_to_le16(fifo_watermark);
err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_THL_ADDR,
err = hw->tf->write(hw->dev, hw->settings->fifo_ops.fifo_th.addr,
sizeof(wdata), (u8 *)&wdata);
out:
mutex_unlock(&hw->lock);
......@@ -223,6 +218,7 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
{
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
int err, acc_sip, gyro_sip, read_len, samples, offset;
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
......@@ -230,7 +226,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
u8 buff[pattern_len];
__le16 fifo_status;
err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_DIFFL_ADDR,
err = hw->tf->read(hw->dev, hw->settings->fifo_ops.fifo_diff.addr,
sizeof(fifo_status), (u8 *)&fifo_status);
if (err < 0)
return err;
......@@ -238,7 +234,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
return 0;
fifo_len = (le16_to_cpu(fifo_status) & ST_LSM6DSX_FIFO_DIFF_MASK) *
fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
ST_LSM6DSX_CHAN_SIZE;
samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
fifo_len = (fifo_len / pattern_len) * pattern_len;
......@@ -345,6 +341,10 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
return err;
}
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
return err;
err = st_lsm6dsx_update_decimators(hw);
if (err < 0)
return err;
......
......@@ -42,8 +42,6 @@
#include "st_lsm6dsx.h"
#define ST_LSM6DSX_REG_ACC_DEC_MASK GENMASK(2, 0)
#define ST_LSM6DSX_REG_GYRO_DEC_MASK GENMASK(5, 3)
#define ST_LSM6DSX_REG_INT1_ADDR 0x0d
#define ST_LSM6DSX_REG_INT2_ADDR 0x0e
#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3)
......@@ -156,25 +154,88 @@ static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.wai = 0x69,
.max_fifo_size = 8192,
.max_fifo_size = 1365,
.id = {
[0] = ST_LSM6DS3_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
.mask = GENMASK(2, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
},
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(11, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
},
{
.wai = 0x69,
.max_fifo_size = 4096,
.max_fifo_size = 682,
.id = {
[0] = ST_LSM6DS3H_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
.mask = GENMASK(2, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
},
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(11, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
},
{
.wai = 0x6a,
.max_fifo_size = 4096,
.max_fifo_size = 682,
.id = {
[0] = ST_LSM6DSL_ID,
[1] = ST_LSM6DSM_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
.mask = GENMASK(2, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
},
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(11, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
},
};
......@@ -462,10 +523,9 @@ static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
struct st_lsm6dsx_hw *hw = sensor->hw;
int err, max_fifo_len;
int err;
max_fifo_len = hw->settings->max_fifo_size / ST_LSM6DSX_SAMPLE_SIZE;
if (val < 1 || val > max_fifo_len)
if (val < 1 || val > hw->settings->max_fifo_size)
return -EINVAL;
err = st_lsm6dsx_update_watermark(sensor, val);
......@@ -646,7 +706,6 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
iio_dev->info = &st_lsm6dsx_acc_info;
sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK;
scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
name);
break;
......@@ -655,7 +714,6 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
iio_dev->info = &st_lsm6dsx_gyro_info;
sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK;
scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
name);
break;
......
......@@ -24,6 +24,7 @@
#include <linux/err.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
......@@ -86,6 +87,8 @@
struct vl6180_data {
struct i2c_client *client;
struct mutex lock;
unsigned int als_gain_milli;
unsigned int als_it_ms;
};
enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX };
......@@ -275,19 +278,17 @@ static const struct iio_chan_spec vl6180_channels[] = {
};
/*
* Columns 3 & 4 represent the same value in decimal and hex notations.
* Kept in order to avoid the datatype conversion while reading the
* hardware_gain.
* Available Ambient Light Sensor gain settings, 1/1000th, and
* corresponding setting for the VL6180_ALS_GAIN register
*/
static const int vl6180_als_gain[8][4] = {
{ 1, 0, 70, VL6180_ALS_GAIN_1 },
{ 1, 250000, 69, VL6180_ALS_GAIN_1_25 },
{ 1, 670000, 68, VL6180_ALS_GAIN_1_67 },
{ 2, 500000, 67, VL6180_ALS_GAIN_2_5 },
{ 5, 0, 66, VL6180_ALS_GAIN_5 },
{ 10, 0, 65, VL6180_ALS_GAIN_10 },
{ 20, 0, 64, VL6180_ALS_GAIN_20 },
{ 40, 0, 71, VL6180_ALS_GAIN_40 }
static const int vl6180_als_gain_tab[8] = {
1000, 1250, 1670, 2500, 5000, 10000, 20000, 40000
};
static const u8 vl6180_als_gain_tab_bits[8] = {
VL6180_ALS_GAIN_1, VL6180_ALS_GAIN_1_25,
VL6180_ALS_GAIN_1_67, VL6180_ALS_GAIN_2_5,
VL6180_ALS_GAIN_5, VL6180_ALS_GAIN_10,
VL6180_ALS_GAIN_20, VL6180_ALS_GAIN_40
};
static int vl6180_read_raw(struct iio_dev *indio_dev,
......@@ -295,7 +296,7 @@ static int vl6180_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct vl6180_data *data = iio_priv(indio_dev);
int ret, i;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
......@@ -306,19 +307,20 @@ static int vl6180_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
ret = vl6180_read_word(data->client, VL6180_ALS_IT);
if (ret < 0)
return ret;
*val = 0; /* 1 count = 1ms (0 = 1ms) */
*val2 = (ret + 1) * 1000; /* convert to seconds */
*val = data->als_it_ms;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_LIGHT:
*val = 0; /* one ALS count is 0.32 Lux */
*val2 = 320000;
break;
/* one ALS count is 0.32 Lux @ gain 1, IT 100 ms */
*val = 32000; /* 0.32 * 1000 * 100 */
*val2 = data->als_gain_milli * data->als_it_ms;
return IIO_VAL_FRACTIONAL;
case IIO_DISTANCE:
*val = 0; /* sensor reports mm, scale to meter */
*val2 = 1000;
......@@ -329,17 +331,11 @@ static int vl6180_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_HARDWAREGAIN:
ret = vl6180_read_byte(data->client, VL6180_ALS_GAIN);
if (ret < 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(vl6180_als_gain); i++) {
if (ret == vl6180_als_gain[i][2]) {
*val = vl6180_als_gain[i][0];
*val2 = vl6180_als_gain[i][1];
}
}
*val = data->als_gain_milli;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
......@@ -365,37 +361,53 @@ static int vl6180_hold(struct vl6180_data *data, bool hold)
static int vl6180_set_als_gain(struct vl6180_data *data, int val, int val2)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(vl6180_als_gain); i++) {
if (val == vl6180_als_gain[i][0] &&
val2 == vl6180_als_gain[i][1]) {
mutex_lock(&data->lock);
ret = vl6180_hold(data, true);
if (ret < 0)
goto fail;
ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
vl6180_als_gain[i][3]);
fail:
vl6180_hold(data, false);
mutex_unlock(&data->lock);
return ret;
}
}
int i, ret, gain;
return -EINVAL;
if (val < 1 || val > 40)
return -EINVAL;
gain = (val * 1000000 + val2) / 1000;
if (gain < 1 || gain > 40000)
return -EINVAL;
i = find_closest(gain, vl6180_als_gain_tab,
ARRAY_SIZE(vl6180_als_gain_tab));
mutex_lock(&data->lock);
ret = vl6180_hold(data, true);
if (ret < 0)
goto fail;
ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
vl6180_als_gain_tab_bits[i]);
if (ret >= 0)
data->als_gain_milli = vl6180_als_gain_tab[i];
fail:
vl6180_hold(data, false);
mutex_unlock(&data->lock);
return ret;
}
static int vl6180_set_it(struct vl6180_data *data, int val2)
static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
{
int ret;
int ret, it_ms;
it_ms = (val2 + 500) / 1000; /* round to ms */
if (val != 0 || it_ms < 1 || it_ms > 512)
return -EINVAL;
mutex_lock(&data->lock);
ret = vl6180_hold(data, true);
if (ret < 0)
goto fail;
ret = vl6180_write_word(data->client, VL6180_ALS_IT,
(val2 - 500) / 1000); /* write value in ms */
ret = vl6180_write_word(data->client, VL6180_ALS_IT, it_ms - 1);
if (ret >= 0)
data->als_it_ms = it_ms;
fail:
vl6180_hold(data, false);
mutex_unlock(&data->lock);
......@@ -411,10 +423,8 @@ static int vl6180_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
if (val != 0 || val2 < 500 || val2 >= 512500)
return -EINVAL;
return vl6180_set_it(data, val, val2);
return vl6180_set_it(data, val2);
case IIO_CHAN_INFO_HARDWAREGAIN:
if (chan->type != IIO_LIGHT)
return -EINVAL;
......@@ -467,11 +477,13 @@ static int vl6180_init(struct vl6180_data *data)
return ret;
/* ALS integration time: 100ms */
data->als_it_ms = 100;
ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
if (ret < 0)
return ret;
/* ALS gain: 1 */
data->als_gain_milli = 1000;
ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
if (ret < 0)
return ret;
......
......@@ -317,7 +317,14 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
},
.drdy_irq = {
/* drdy line is routed drdy pin */
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x22,
.value = BIT(2),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -359,9 +366,14 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.mask = 0x10,
},
.drdy_irq = {
.addr = 0x62,
.mask_int1 = 0x01,
.addr_stat_drdy = 0x67,
.int1 = {
.addr = 0x62,
.mask = 0x01,
},
.stat_drdy = {
.addr = 0x67,
.mask = 0x07,
},
},
.multi_read_bit = false,
.bootime = 2,
......
......@@ -280,14 +280,28 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.mask = 0x04,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x04,
.mask_int2 = 0x20,
.int1 = {
.addr = 0x22,
.mask = 0x04,
.addr_od = 0x22,
.mask_od = 0x40,
},
.int2 = {
.addr = 0x22,
.mask = 0x20,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x03,
},
},
.sim = {
.addr = 0x20,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -335,8 +349,9 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.addr = 0x20,
.mask = 0x04,
},
.drdy_irq = {
.addr = 0,
.sim = {
.addr = 0x20,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -388,14 +403,22 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.mask = 0x04,
},
.drdy_irq = {
.addr = 0x23,
.mask_int1 = 0x01,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x23,
.mask = 0x01,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x03,
},
},
.sim = {
.addr = 0x20,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -449,14 +472,22 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.mask = 0x02,
},
.drdy_irq = {
.addr = 0x12,
.mask_int1 = 0x04,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x12,
.mask = 0x04,
.addr_od = 0x12,
.mask_od = 0x40,
},
.addr_ihl = 0x12,
.mask_ihl = 0x80,
.addr_od = 0x12,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x03,
},
},
.sim = {
.addr = 0x10,
.value = BIT(0),
},
.multi_read_bit = false,
.bootime = 2,
......@@ -605,7 +636,8 @@ int st_press_common_probe(struct iio_dev *indio_dev)
press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
/* Some devices don't support a data ready pin. */
if (!pdata && press_data->sensor_settings->drdy_irq.addr)
if (!pdata && (press_data->sensor_settings->drdy_irq.int1.addr ||
press_data->sensor_settings->drdy_irq.int2.addr))
pdata = (struct st_sensors_platform_data *)&default_press_pdata;
err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
......
......@@ -32,6 +32,16 @@ config LIDAR_LITE_V2
To compile this driver as a module, choose M here: the
module will be called pulsedlight-lite-v2
config RFD77402
tristate "RFD77402 ToF sensor"
depends on I2C
help
Say Y to build a driver for the RFD77420 Time-of-Flight (distance)
sensor module with I2C interface.
To compile this driver as a module, choose M here: the
module will be called rfd77402.
config SRF04
tristate "Devantech SRF04 ultrasonic ranger sensor"
depends on GPIOLIB
......
......@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9500) += sx9500.o
/*
* rfd77402.c - Support for RF Digital RFD77402 Time-of-Flight (distance) sensor
*
* Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
*
* 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.
*
* 7-bit I2C slave address 0x4c
*
* TODO: interrupt
* https://media.digikey.com/pdf/Data%20Sheets/RF%20Digital%20PDFs/RFD77402.pdf
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#define RFD77402_DRV_NAME "rfd77402"
#define RFD77402_ICSR 0x00 /* Interrupt Control Status Register */
#define RFD77402_ICSR_INT_MODE BIT(2)
#define RFD77402_ICSR_INT_POL BIT(3)
#define RFD77402_ICSR_RESULT BIT(4)
#define RFD77402_ICSR_M2H_MSG BIT(5)
#define RFD77402_ICSR_H2M_MSG BIT(6)
#define RFD77402_ICSR_RESET BIT(7)
#define RFD77402_CMD_R 0x04
#define RFD77402_CMD_SINGLE 0x01
#define RFD77402_CMD_STANDBY 0x10
#define RFD77402_CMD_MCPU_OFF 0x11
#define RFD77402_CMD_MCPU_ON 0x12
#define RFD77402_CMD_RESET BIT(6)
#define RFD77402_CMD_VALID BIT(7)
#define RFD77402_STATUS_R 0x06
#define RFD77402_STATUS_PM_MASK GENMASK(4, 0)
#define RFD77402_STATUS_STANDBY 0x00
#define RFD77402_STATUS_MCPU_OFF 0x10
#define RFD77402_STATUS_MCPU_ON 0x18
#define RFD77402_RESULT_R 0x08
#define RFD77402_RESULT_DIST_MASK GENMASK(12, 2)
#define RFD77402_RESULT_ERR_MASK GENMASK(14, 13)
#define RFD77402_RESULT_VALID BIT(15)
#define RFD77402_PMU_CFG 0x14
#define RFD77402_PMU_MCPU_INIT BIT(9)
#define RFD77402_I2C_INIT_CFG 0x1c
#define RFD77402_I2C_ADDR_INCR BIT(0)
#define RFD77402_I2C_DATA_INCR BIT(2)
#define RFD77402_I2C_HOST_DEBUG BIT(5)
#define RFD77402_I2C_MCPU_DEBUG BIT(6)
#define RFD77402_CMD_CFGR_A 0x0c
#define RFD77402_CMD_CFGR_B 0x0e
#define RFD77402_HFCFG_0 0x20
#define RFD77402_HFCFG_1 0x22
#define RFD77402_HFCFG_2 0x24
#define RFD77402_HFCFG_3 0x26
#define RFD77402_MOD_CHIP_ID 0x28
/* magic configuration values from datasheet */
static const struct {
u8 reg;
u16 val;
} rf77402_tof_config[] = {
{RFD77402_CMD_CFGR_A, 0xe100},
{RFD77402_CMD_CFGR_B, 0x10ff},
{RFD77402_HFCFG_0, 0x07d0},
{RFD77402_HFCFG_1, 0x5008},
{RFD77402_HFCFG_2, 0xa041},
{RFD77402_HFCFG_3, 0x45d4},
};
struct rfd77402_data {
struct i2c_client *client;
/* Serialize reads from the sensor */
struct mutex lock;
};
static const struct iio_chan_spec rfd77402_channels[] = {
{
.type = IIO_DISTANCE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
{
int ret;
ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
state | RFD77402_CMD_VALID);
if (ret < 0)
return ret;
usleep_range(10000, 20000);
ret = i2c_smbus_read_word_data(data->client, RFD77402_STATUS_R);
if (ret < 0)
return ret;
if ((ret & RFD77402_STATUS_PM_MASK) != check)
return -ENODEV;
return 0;
}
static int rfd77402_measure(struct rfd77402_data *data)
{
int ret;
int tries = 10;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
RFD77402_CMD_SINGLE |
RFD77402_CMD_VALID);
if (ret < 0)
goto err;
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, RFD77402_ICSR);
if (ret < 0)
goto err;
if (ret & RFD77402_ICSR_RESULT)
break;
msleep(20);
}
if (tries < 0) {
ret = -ETIMEDOUT;
goto err;
}
ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R);
if (ret < 0)
goto err;
if ((ret & RFD77402_RESULT_ERR_MASK) ||
!(ret & RFD77402_RESULT_VALID)) {
ret = -EIO;
goto err;
}
return (ret & RFD77402_RESULT_DIST_MASK) >> 2;
err:
rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
return ret;
}
static int rfd77402_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct rfd77402_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
ret = rfd77402_measure(data);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* 1 LSB is 1 mm */
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static const struct iio_info rfd77402_info = {
.read_raw = rfd77402_read_raw,
};
static int rfd77402_init(struct rfd77402_data *data)
{
int ret, i;
ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
if (ret < 0)
return ret;
/* configure INT pad as push-pull, active low */
ret = i2c_smbus_write_byte_data(data->client, RFD77402_ICSR,
RFD77402_ICSR_INT_MODE);
if (ret < 0)
return ret;
/* I2C configuration */
ret = i2c_smbus_write_word_data(data->client, RFD77402_I2C_INIT_CFG,
RFD77402_I2C_ADDR_INCR |
RFD77402_I2C_DATA_INCR |
RFD77402_I2C_HOST_DEBUG |
RFD77402_I2C_MCPU_DEBUG);
if (ret < 0)
return ret;
/* set initialization */
ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500);
if (ret < 0)
return ret;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
if (ret < 0)
return ret;
/* set initialization */
ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600);
if (ret < 0)
return ret;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(rf77402_tof_config); i++) {
ret = i2c_smbus_write_word_data(data->client,
rf77402_tof_config[i].reg,
rf77402_tof_config[i].val);
if (ret < 0)
return ret;
}
ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
return ret;
}
static int rfd77402_powerdown(struct rfd77402_data *data)
{
return rfd77402_set_state(data, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
}
static int rfd77402_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rfd77402_data *data;
struct iio_dev *indio_dev;
int ret;
ret = i2c_smbus_read_word_data(client, RFD77402_MOD_CHIP_ID);
if (ret < 0)
return ret;
if (ret != 0xad01 && ret != 0xad02) /* known chip ids */
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;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &rfd77402_info;
indio_dev->channels = rfd77402_channels;
indio_dev->num_channels = ARRAY_SIZE(rfd77402_channels);
indio_dev->name = RFD77402_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = rfd77402_init(data);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto err_powerdown;
return 0;
err_powerdown:
rfd77402_powerdown(data);
return ret;
}
static int rfd77402_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
rfd77402_powerdown(iio_priv(indio_dev));
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rfd77402_suspend(struct device *dev)
{
struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return rfd77402_powerdown(data);
}
static int rfd77402_resume(struct device *dev)
{
struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return rfd77402_init(data);
}
#endif
static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume);
static const struct i2c_device_id rfd77402_id[] = {
{ "rfd77402", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, rfd77402_id);
static struct i2c_driver rfd77402_driver = {
.driver = {
.name = RFD77402_DRV_NAME,
.pm = &rfd77402_pm_ops,
},
.probe = rfd77402_probe,
.remove = rfd77402_remove,
.id_table = rfd77402_id,
};
module_i2c_driver(rfd77402_driver);
MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("RFD77402 Time-of-Flight sensor driver");
MODULE_LICENSE("GPL");
......@@ -162,6 +162,7 @@ struct ad7192_state {
u32 scale_avail[8][2];
u8 gpocon;
u8 devid;
struct mutex lock; /* protect sensor state */
struct ad_sigma_delta sd;
};
......@@ -461,10 +462,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
*val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0];
*val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1];
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
*val = 0;
......@@ -508,6 +509,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
......@@ -521,6 +523,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
ad7192_calibrate_all(st);
break;
}
mutex_unlock(&st->lock);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (!val) {
......@@ -630,6 +633,8 @@ static int ad7192_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->avdd = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->avdd))
return PTR_ERR(st->avdd);
......
......@@ -174,7 +174,7 @@ struct tsl2X7X_chip {
struct i2c_client *client;
u16 prox_data;
struct tsl2x7x_als_info als_cur_info;
struct tsl2x7x_settings tsl2x7x_settings;
struct tsl2x7x_settings settings;
struct tsl2X7X_platform_data *pdata;
int als_time_scale;
int als_saturation;
......@@ -390,9 +390,9 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
lux = 0;
} else {
ch0lux = DIV_ROUND_UP(ch0 * p->ch0,
tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
tsl2X7X_als_gainadj[chip->settings.als_gain]);
ch1lux = DIV_ROUND_UP(ch1 * p->ch1,
tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
tsl2X7X_als_gainadj[chip->settings.als_gain]);
lux = ch0lux - ch1lux;
}
......@@ -419,7 +419,7 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
*/
lux64 = lux;
lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
lux64 = lux64 * chip->settings.als_gain_trim;
lux64 >>= 8;
lux = lux64;
lux = (lux + 500) / 1000;
......@@ -514,12 +514,10 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
{
/* If Operational settings defined elsewhere.. */
if (chip->pdata && chip->pdata->platform_default_settings)
memcpy(&chip->tsl2x7x_settings,
chip->pdata->platform_default_settings,
memcpy(&chip->settings, chip->pdata->platform_default_settings,
sizeof(tsl2x7x_default_settings));
else
memcpy(&chip->tsl2x7x_settings,
&tsl2x7x_default_settings,
memcpy(&chip->settings, &tsl2x7x_default_settings,
sizeof(tsl2x7x_default_settings));
/* Load up the proper lux table. */
......@@ -542,9 +540,7 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
{
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
int gain_trim_val;
int ret;
int lux_val;
int ret, lux_val;
ret = i2c_smbus_read_byte_data(chip->client,
TSL2X7X_CMD_REG | TSL2X7X_CNTRL);
......@@ -575,16 +571,16 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
return lux_val;
}
gain_trim_val = ((chip->tsl2x7x_settings.als_cal_target)
* chip->tsl2x7x_settings.als_gain_trim) / lux_val;
if ((gain_trim_val < 250) || (gain_trim_val > 4000))
ret = (chip->settings.als_cal_target * chip->settings.als_gain_trim) /
lux_val;
if (ret < 250 || ret > 4000)
return -ERANGE;
chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
chip->settings.als_gain_trim = ret;
dev_info(&chip->client->dev,
"%s als_calibrate completed\n", chip->client->name);
return (int)gain_trim_val;
return ret;
}
static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
......@@ -602,34 +598,30 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
chip->pdata->power_on(indio_dev);
/* Non calculated parameters */
chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
chip->tsl2x7x_settings.prx_time;
chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
chip->tsl2x7x_settings.wait_time;
chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
chip->tsl2x7x_settings.prox_config;
chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prx_time;
chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time;
chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = chip->settings.prox_config;
chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
(chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
(chip->settings.als_thresh_low) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
(chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
(chip->settings.als_thresh_low >> 8) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
(chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
(chip->settings.als_thresh_high) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
(chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
chip->tsl2x7x_settings.persistence;
(chip->settings.als_thresh_high >> 8) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = chip->settings.persistence;
chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
chip->tsl2x7x_settings.prox_pulse_count;
chip->settings.prox_pulse_count;
chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
(chip->tsl2x7x_settings.prox_thres_low) & 0xFF;
(chip->settings.prox_thres_low) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] =
(chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF;
(chip->settings.prox_thres_low >> 8) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
(chip->tsl2x7x_settings.prox_thres_high) & 0xFF;
(chip->settings.prox_thres_high) & 0xFF;
chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] =
(chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF;
(chip->settings.prox_thres_high >> 8) & 0xFF;
/* and make sure we're not already on */
if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
......@@ -639,7 +631,7 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
}
/* determine als integration register */
als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
als_count = (chip->settings.als_time * 100 + 135) / 270;
if (!als_count)
als_count = 1; /* ensure at least one cycle */
......@@ -649,9 +641,9 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
/* Set the gain based on tsl2x7x_settings struct */
chip->tsl2x7x_config[TSL2X7X_GAIN] =
chip->tsl2x7x_settings.als_gain |
(TSL2X7X_mA100 | TSL2X7X_DIODE1)
| ((chip->tsl2x7x_settings.prox_gain) << 2);
chip->settings.als_gain |
(TSL2X7X_mA100 | TSL2X7X_DIODE1) |
(chip->settings.prox_gain << 2);
/* set chip struct re scaling and saturation */
chip->als_saturation = als_count * 922; /* 90% of full scale */
......@@ -706,15 +698,15 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
if (chip->tsl2x7x_settings.interrupts_en != 0) {
if (chip->settings.interrupts_en != 0) {
dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
(chip->tsl2x7x_settings.interrupts_en == 0x30))
if ((chip->settings.interrupts_en == 0x20) ||
(chip->settings.interrupts_en == 0x30))
reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
reg_val |= chip->tsl2x7x_settings.interrupts_en;
reg_val |= chip->settings.interrupts_en;
ret = i2c_smbus_write_byte_data(chip->client,
(TSL2X7X_CMD_REG |
TSL2X7X_CNTRL), reg_val);
......@@ -837,25 +829,25 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
u8 tmp_irq_settings;
u8 current_state = chip->tsl2x7x_chip_status;
if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
if (chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
dev_err(&chip->client->dev,
"max prox samples cal is too big: %d\n",
chip->tsl2x7x_settings.prox_max_samples_cal);
chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
chip->settings.prox_max_samples_cal);
chip->settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
}
/* have to stop to change settings */
tsl2x7x_chip_off(indio_dev);
/* Enable proximity detection save just in case prox not wanted yet*/
tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
tmp_irq_settings = chip->settings.interrupts_en;
chip->settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
/*turn on device if not already on*/
tsl2x7x_chip_on(indio_dev);
/*gather the samples*/
for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
for (i = 0; i < chip->settings.prox_max_samples_cal; i++) {
usleep_range(15000, 17500);
tsl2x7x_get_prox(indio_dev);
prox_history[i] = chip->prox_data;
......@@ -866,18 +858,17 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
tsl2x7x_chip_off(indio_dev);
calP = &prox_stat_data[PROX_STAT_CAL];
tsl2x7x_prox_calculate(prox_history,
chip->tsl2x7x_settings.prox_max_samples_cal,
calP);
chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
chip->settings.prox_max_samples_cal, calP);
chip->settings.prox_thres_high = (calP->max << 1) - calP->mean;
dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
calP->min, calP->mean, calP->max);
dev_info(&chip->client->dev,
"%s proximity threshold set to %d\n",
chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
chip->client->name, chip->settings.prox_thres_high);
/* back to the way they were */
chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
chip->settings.interrupts_en = tmp_irq_settings;
if (current_state == TSL2X7X_CHIP_WORKING)
tsl2x7x_chip_on(indio_dev);
}
......@@ -907,46 +898,6 @@ static ssize_t in_proximity0_calibscale_available_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
}
static ssize_t in_illuminance0_integration_time_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
int y, z;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
y /= 1000;
z %= 1000;
return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
}
static ssize_t in_illuminance0_integration_time_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
struct tsl2x7x_parse_result result;
int ret;
ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
if (ret)
return ret;
result.fract /= 3;
chip->tsl2x7x_settings.als_time =
TSL2X7X_MAX_TIMER_CNT - (u8)result.fract;
dev_info(&chip->client->dev, "%s: als time = %d",
__func__, chip->tsl2x7x_settings.als_time);
tsl2x7x_invoke_change(indio_dev);
return IIO_VAL_INT_PLUS_MICRO;
}
static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
".00272 - .696");
......@@ -956,8 +907,7 @@ static ssize_t in_illuminance0_target_input_show(struct device *dev,
{
struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
return snprintf(buf, PAGE_SIZE, "%d\n",
chip->tsl2x7x_settings.als_cal_target);
return snprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target);
}
static ssize_t in_illuminance0_target_input_store(struct device *dev,
......@@ -973,7 +923,7 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev,
return -EINVAL;
if (value)
chip->tsl2x7x_settings.als_cal_target = value;
chip->settings.als_cal_target = value;
ret = tsl2x7x_invoke_change(indio_dev);
if (ret < 0)
......@@ -991,9 +941,9 @@ static ssize_t in_intensity0_thresh_period_show(struct device *dev,
int y, z, filter_delay;
/* Determine integration time */
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->settings.als_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
filter_delay = z * (chip->settings.persistence & 0x0F);
y = filter_delay / 1000;
z = filter_delay % 1000;
......@@ -1014,14 +964,14 @@ static ssize_t in_intensity0_thresh_period_store(struct device *dev,
if (ret)
return ret;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->settings.als_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
filter_delay =
DIV_ROUND_UP((result.integer * 1000) + result.fract, z);
chip->tsl2x7x_settings.persistence &= 0xF0;
chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
chip->settings.persistence &= 0xF0;
chip->settings.persistence |= (filter_delay & 0x0F);
dev_info(&chip->client->dev, "%s: als persistence = %d",
__func__, filter_delay);
......@@ -1041,9 +991,9 @@ static ssize_t in_proximity0_thresh_period_show(struct device *dev,
int y, z, filter_delay;
/* Determine integration time */
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->settings.prx_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
filter_delay = z * ((chip->settings.persistence & 0xF0) >> 4);
y = filter_delay / 1000;
z = filter_delay % 1000;
......@@ -1064,14 +1014,14 @@ static ssize_t in_proximity0_thresh_period_store(struct device *dev,
if (ret)
return ret;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->settings.prx_time) + 1;
z = y * TSL2X7X_MIN_ITIME;
filter_delay =
DIV_ROUND_UP((result.integer * 1000) + result.fract, z);
chip->tsl2x7x_settings.persistence &= 0x0F;
chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
chip->settings.persistence &= 0x0F;
chip->settings.persistence |= ((filter_delay << 4) & 0xF0);
dev_info(&chip->client->dev, "%s: prox persistence = %d",
__func__, filter_delay);
......@@ -1205,9 +1155,9 @@ static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
int ret;
if (chan->type == IIO_INTENSITY)
ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
ret = !!(chip->settings.interrupts_en & 0x10);
else
ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
ret = !!(chip->settings.interrupts_en & 0x20);
return ret;
}
......@@ -1223,14 +1173,14 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
if (chan->type == IIO_INTENSITY) {
if (val)
chip->tsl2x7x_settings.interrupts_en |= 0x10;
chip->settings.interrupts_en |= 0x10;
else
chip->tsl2x7x_settings.interrupts_en &= 0x20;
chip->settings.interrupts_en &= 0x20;
} else {
if (val)
chip->tsl2x7x_settings.interrupts_en |= 0x20;
chip->settings.interrupts_en |= 0x20;
else
chip->tsl2x7x_settings.interrupts_en &= 0x10;
chip->settings.interrupts_en &= 0x10;
}
ret = tsl2x7x_invoke_change(indio_dev);
......@@ -1255,11 +1205,11 @@ static int tsl2x7x_write_event_value(struct iio_dev *indio_dev,
if (chan->type == IIO_INTENSITY) {
switch (dir) {
case IIO_EV_DIR_RISING:
chip->tsl2x7x_settings.als_thresh_high = val;
chip->settings.als_thresh_high = val;
ret = 0;
break;
case IIO_EV_DIR_FALLING:
chip->tsl2x7x_settings.als_thresh_low = val;
chip->settings.als_thresh_low = val;
ret = 0;
break;
default:
......@@ -1268,11 +1218,11 @@ static int tsl2x7x_write_event_value(struct iio_dev *indio_dev,
} else {
switch (dir) {
case IIO_EV_DIR_RISING:
chip->tsl2x7x_settings.prox_thres_high = val;
chip->settings.prox_thres_high = val;
ret = 0;
break;
case IIO_EV_DIR_FALLING:
chip->tsl2x7x_settings.prox_thres_low = val;
chip->settings.prox_thres_low = val;
ret = 0;
break;
default:
......@@ -1305,11 +1255,11 @@ static int tsl2x7x_read_event_value(struct iio_dev *indio_dev,
if (chan->type == IIO_INTENSITY) {
switch (dir) {
case IIO_EV_DIR_RISING:
*val = chip->tsl2x7x_settings.als_thresh_high;
*val = chip->settings.als_thresh_high;
ret = IIO_VAL_INT;
break;
case IIO_EV_DIR_FALLING:
*val = chip->tsl2x7x_settings.als_thresh_low;
*val = chip->settings.als_thresh_low;
ret = IIO_VAL_INT;
break;
default:
......@@ -1318,11 +1268,11 @@ static int tsl2x7x_read_event_value(struct iio_dev *indio_dev,
} else {
switch (dir) {
case IIO_EV_DIR_RISING:
*val = chip->tsl2x7x_settings.prox_thres_high;
*val = chip->settings.prox_thres_high;
ret = IIO_VAL_INT;
break;
case IIO_EV_DIR_FALLING:
*val = chip->tsl2x7x_settings.prox_thres_low;
*val = chip->settings.prox_thres_low;
ret = IIO_VAL_INT;
break;
default:
......@@ -1379,18 +1329,20 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
break;
case IIO_CHAN_INFO_CALIBSCALE:
if (chan->type == IIO_LIGHT)
*val =
tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
*val = tsl2X7X_als_gainadj[chip->settings.als_gain];
else
*val =
tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
*val = tsl2X7X_prx_gainadj[chip->settings.prox_gain];
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_CALIBBIAS:
*val = chip->tsl2x7x_settings.als_gain_trim;
*val = chip->settings.als_gain_trim;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_INT_TIME:
*val = (TSL2X7X_MAX_TIMER_CNT - chip->settings.als_time) + 1;
*val2 = ((*val * TSL2X7X_MIN_ITIME) % 1000) / 1000;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
ret = -EINVAL;
}
......@@ -1411,13 +1363,13 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
if (chan->type == IIO_INTENSITY) {
switch (val) {
case 1:
chip->tsl2x7x_settings.als_gain = 0;
chip->settings.als_gain = 0;
break;
case 8:
chip->tsl2x7x_settings.als_gain = 1;
chip->settings.als_gain = 1;
break;
case 16:
chip->tsl2x7x_settings.als_gain = 2;
chip->settings.als_gain = 2;
break;
case 120:
switch (chip->id) {
......@@ -1428,7 +1380,7 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
case tmd2772:
return -EINVAL;
}
chip->tsl2x7x_settings.als_gain = 3;
chip->settings.als_gain = 3;
break;
case 128:
switch (chip->id) {
......@@ -1439,7 +1391,7 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
case tmd2771:
return -EINVAL;
}
chip->tsl2x7x_settings.als_gain = 3;
chip->settings.als_gain = 3;
break;
default:
return -EINVAL;
......@@ -1447,16 +1399,16 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
} else {
switch (val) {
case 1:
chip->tsl2x7x_settings.prox_gain = 0;
chip->settings.prox_gain = 0;
break;
case 2:
chip->tsl2x7x_settings.prox_gain = 1;
chip->settings.prox_gain = 1;
break;
case 4:
chip->tsl2x7x_settings.prox_gain = 2;
chip->settings.prox_gain = 2;
break;
case 8:
chip->tsl2x7x_settings.prox_gain = 3;
chip->settings.prox_gain = 3;
break;
default:
return -EINVAL;
......@@ -1464,9 +1416,15 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_CALIBBIAS:
chip->tsl2x7x_settings.als_gain_trim = val;
chip->settings.als_gain_trim = val;
break;
case IIO_CHAN_INFO_INT_TIME:
chip->settings.als_time =
TSL2X7X_MAX_TIMER_CNT - (val2 / TSL2X7X_MIN_ITIME);
dev_info(&chip->client->dev, "%s: als time = %d",
__func__, chip->settings.als_time);
break;
default:
return -EINVAL;
}
......@@ -1478,8 +1436,6 @@ static DEVICE_ATTR_RO(in_proximity0_calibscale_available);
static DEVICE_ATTR_RO(in_illuminance0_calibscale_available);
static DEVICE_ATTR_RW(in_illuminance0_integration_time);
static DEVICE_ATTR_RW(in_illuminance0_target_input);
static DEVICE_ATTR_WO(in_illuminance0_calibrate);
......@@ -1559,7 +1515,6 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
static struct attribute *tsl2x7x_ALS_device_attrs[] = {
&dev_attr_in_illuminance0_calibscale_available.attr,
&dev_attr_in_illuminance0_integration_time.attr,
&iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr,
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
......@@ -1574,7 +1529,6 @@ static struct attribute *tsl2x7x_PRX_device_attrs[] = {
static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
&dev_attr_in_illuminance0_calibscale_available.attr,
&dev_attr_in_illuminance0_integration_time.attr,
&iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr,
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
......@@ -1591,7 +1545,6 @@ static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
&dev_attr_in_illuminance0_calibscale_available.attr,
&dev_attr_in_illuminance0_integration_time.attr,
&iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr,
&dev_attr_in_illuminance0_target_input.attr,
&dev_attr_in_illuminance0_calibrate.attr,
......@@ -1724,7 +1677,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_INT_TIME),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
......@@ -1763,7 +1717,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED)
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_INT_TIME),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
......@@ -1811,7 +1766,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_INT_TIME),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
......
......@@ -80,13 +80,11 @@
* @us: actual spi_device
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
* @lock: protect sensor data
* @buf_lock: mutex to protect tx, rx and write frequency
**/
struct ade7753_state {
struct spi_device *us;
struct mutex buf_lock;
struct mutex lock; /* protect sensor data */
u8 tx[ADE7753_MAX_TX] ____cacheline_aligned;
u8 rx[ADE7753_MAX_RX];
};
......@@ -109,6 +107,19 @@ static int ade7753_spi_write_reg_8(struct device *dev,
return ret;
}
static int __ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
return spi_write(st->us, st->tx, 3);
}
static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
......@@ -117,10 +128,7 @@ static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
ret = spi_write(st->us, st->tx, 3);
ret = __ade7753_spi_write_reg_16(dev, reg_address, value);
mutex_unlock(&st->buf_lock);
return ret;
......@@ -485,7 +493,7 @@ static ssize_t ade7753_write_frequency(struct device *dev,
if (!val)
return -EINVAL;
mutex_lock(&st->lock);
mutex_lock(&st->buf_lock);
t = 27900 / val;
if (t > 0)
......@@ -503,10 +511,10 @@ static ssize_t ade7753_write_frequency(struct device *dev,
reg &= ~(3 << 11);
reg |= t << 11;
ret = ade7753_spi_write_reg_16(dev, ADE7753_MODE, reg);
ret = __ade7753_spi_write_reg_16(dev, ADE7753_MODE, reg);
out:
mutex_unlock(&st->lock);
mutex_unlock(&st->buf_lock);
return ret ? ret : len;
}
......@@ -581,7 +589,6 @@ static int ade7753_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
mutex_init(&st->lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
......
......@@ -231,6 +231,7 @@ struct hid_sensor_common {
unsigned usage_id;
atomic_t data_ready;
atomic_t user_requested_state;
atomic_t runtime_pm_enable;
int poll_interval;
int raw_hystersis;
int latency_ms;
......
......@@ -130,29 +130,40 @@ struct st_sensor_das {
u8 mask;
};
/**
* struct st_sensor_int_drdy - ST sensor device drdy line parameters
* @addr: address of INT drdy register.
* @mask: mask to enable drdy line.
* @addr_od: address to enable/disable Open Drain on the INT line.
* @mask_od: mask to enable/disable Open Drain on the INT line.
*/
struct st_sensor_int_drdy {
u8 addr;
u8 mask;
u8 addr_od;
u8 mask_od;
};
/**
* struct st_sensor_data_ready_irq - ST sensor device data-ready interrupt
* @addr: address of the register.
* @mask_int1: mask to enable/disable IRQ on INT1 pin.
* @mask_int2: mask to enable/disable IRQ on INT2 pin.
* struct int1 - data-ready configuration register for INT1 pin.
* struct int2 - data-ready configuration register for INT2 pin.
* @addr_ihl: address to enable/disable active low on the INT lines.
* @mask_ihl: mask to enable/disable active low on the INT lines.
* @addr_od: address to enable/disable Open Drain on the INT lines.
* @mask_od: mask to enable/disable Open Drain on the INT lines.
* @addr_stat_drdy: address to read status of DRDY (data ready) interrupt
* struct stat_drdy - status register of DRDY (data ready) interrupt.
* struct ig1 - represents the Interrupt Generator 1 of sensors.
* @en_addr: address of the enable ig1 register.
* @en_mask: mask to write the on/off value for enable.
*/
struct st_sensor_data_ready_irq {
u8 addr;
u8 mask_int1;
u8 mask_int2;
struct st_sensor_int_drdy int1;
struct st_sensor_int_drdy int2;
u8 addr_ihl;
u8 mask_ihl;
u8 addr_od;
u8 mask_od;
u8 addr_stat_drdy;
struct {
u8 addr;
u8 mask;
} stat_drdy;
struct {
u8 en_addr;
u8 en_mask;
......
......@@ -365,7 +365,6 @@ unsigned int iio_get_time_res(const struct iio_dev *indio_dev);
#define INDIO_MAX_RAW_ELEMENTS 4
struct iio_trigger; /* forward declaration */
struct iio_dev;
/**
* struct iio_info - constant information about device
......
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