Commit 35ea984d authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

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

Jonathan writes:

Second set of IIO new drivers, functionality and cleanups for the 4.5 cycle.

The big one here is the configfs support which has been a long time in the
works but should allow for cleaner ways to do instantiation of those elements
of IIO that aren't directly connected to specific hardware. Lots of cool new
stuff we can use this for in the works!

New core stuff (basically all configfs support related)
* Configfs support
  - Core support (was waiting for a configfs patch that went in around 4.4rc2)
  - A little fixlet to add a configfs.h to contain a reference to the
    configfs_subsystem structure.
* Some infrastructure to simplify handling of software based triggers
  (i.e. ones with no actual hardware associated with them)
* A high resolution timer based trigger.  This has been around for years
    but until the configfs support was ready we didn't have a sensible way
    of instantiating instances of it (the method used for the sysfs_trigger
    has never been really satisfactory)

New Device Support
* AMS iAQ Volatile Organic Compounds sensor support.
* Freescale imx7d ADC driver
* Maxim MAX30100 oximeter driver (note that for these devices most of the
  smart stuff will be in userspace - effectively they are just light sensors
  with some interesting led synchronization as far as the kernel is concerned).
* Microchip mcp3421 support added to the mcp3422 driver.
* TI adc124s021 support added to the adc128s052 driver.
* TI ina219, inda226 power monitors. Note that there is an existing hwmon driver
  for these parts, the usecase is somewhat different so it is unclear at this
  point if the hwmon driver will eventually be replaced by a bridge from
  this driver.  In the meantime the Kconfig dependencies should prevent both
  from being built.

New driver functionality
* us8152d power management support.

Cleanups, fixups
* Use list_for_each_entry_safe instead of list_for_each_safe with the entry
  bit coded longhand.
* Select IRQ_WORK for IIO_DUMMY_EVGEN.  This is a fix that somehow got lost
  when the driver was moved so lets do it again.
* st-accel - drop an unused define.
* vz89x, lidar - optimize i2c transactions by using a single i2c tranfers
  instead of multiple calls where supported (fall back to smbus calls as
  before if not).
* Use dev_get_platdata() in staging drivers: tsl2x7x, adcs and frequency
  drivers instead of direct access to the structure element.
parents e59ac747 c34c1819
What: /config/iio
Date: October 2015
KernelVersion: 4.4
Contact: linux-iio@vger.kernel.org
Description:
This represents Industrial IO configuration entry point
directory. It contains sub-groups corresponding to IIO
objects.
What: /config/iio/triggers
Date: October 2015
KernelVersion: 4.4
Description:
Industrial IO software triggers directory.
What: /config/iio/triggers/hrtimers
Date: October 2015
KernelVersion: 4.4
Description:
High resolution timers directory. Creating a directory here
will result in creating a hrtimer trigger in the IIO subsystem.
......@@ -20,6 +20,7 @@ adi,adt7476 +/-1C TDM Extended Temp Range I.C
adi,adt7490 +/-1C TDM Extended Temp Range I.C
adi,adxl345 Three-Axis Digital Accelerometer
adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
ams,iaq-core AMS iAQ-Core VOC Sensor
at,24c08 i2c serial eeprom (24cxx)
atmel,24c00 i2c serial eeprom (24cxx)
atmel,24c01 i2c serial eeprom (24cxx)
......
Freescale imx7d ADC bindings
The devicetree bindings are for the ADC driver written for
imx7d SoC.
Required properties:
- compatible: Should be "fsl,imx7d-adc"
- reg: Offset and length of the register set for the ADC device
- interrupts: The interrupt number for the ADC device
- clocks: The root clock of the ADC controller
- clock-names: Must contain "adc", matching entry in the clocks property
- vref-supply: The regulator supply ADC reference voltage
Example:
adc1: adc@30610000 {
compatible = "fsl,imx7d-adc";
reg = <0x30610000 0x10000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX7D_ADC_ROOT_CLK>;
clock-names = "adc";
vref-supply = <&reg_vcc_3v3_mcu>;
};
* Microchip mcp3422/3/4/6/7/8 chip family (ADC)
* Microchip mcp3421/2/3/4/6/7/8 chip family (ADC)
Required properties:
- compatible: Should be
"microchip,mcp3421" or
"microchip,mcp3422" or
"microchip,mcp3423" or
"microchip,mcp3424" or
......
* Texas Instruments' ADC128S052 and ADC122S021 ADC chip
* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
Required properties:
- compatible: Should be "ti,adc128s052" or "ti,adc122s021"
- compatible: Should be "ti,adc128s052", "ti,adc122s021" or "ti,adc124s021"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage
......
Maxim MAX30100 heart rate and pulse oximeter sensor
* https://datasheets.maximintegrated.com/en/ds/MAX30100.pdf
Required properties:
- compatible: must be "maxim,max30100"
- reg: the I2C address of the sensor
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: the sole interrupt generated by the device
Refer to interrupt-controller/interrupts.txt for generic
interrupt client node bindings.
Example:
max30100@057 {
compatible = "maxim,max30100";
reg = <57>;
interrupt-parent = <&gpio1>;
interrupts = <16 2>;
};
......@@ -7,13 +7,24 @@ Required properties:
Optional properties:
- upisemi,glass-coef: glass attenuation factor - compensation factor of
resolution 1000 for material transmittance.
- upisemi,dark-ths: array of 8 elements containing 16-bit thresholds (adc
counts) corresponding to every scale.
- upisemi,upper-dark-gain: 8-bit dark gain compensation factor(4 int and 4
fractional bits - Q4.4) applied when light > threshold
- upisemi,lower-dark-gain: 8-bit dark gain compensation factor(4 int and 4
fractional bits - Q4.4) applied when light < threshold
- upisemi,continuous: This chip has two power modes: one-shot (chip takes one
measurement and then shuts itself down) and continuous (
chip takes continuous measurements). The one-shot mode is
more power-friendly but the continuous mode may be more
reliable. If this property is specified the continuous
mode will be used instead of the default one-shot one for
raw reads.
If the optional properties are not specified these factors will default to the
values in the below example.
The glass-coef defaults to no compensation for the covering material.
......
Industrial IIO configfs support
1. Overview
Configfs is a filesystem-based manager of kernel objects. IIO uses some
objects that could be easily configured using configfs (e.g.: devices,
triggers).
See Documentation/filesystems/configfs/configfs.txt for more information
about how configfs works.
2. Usage
In order to use configfs support in IIO we need to select it at compile
time via CONFIG_IIO_CONFIGFS config option.
Then, mount the configfs filesystem (usually under /config directory):
$ mkdir /config
$ mount -t configfs none /config
At this point, all default IIO groups will be created and can be accessed
under /config/iio. Next chapters will describe available IIO configuration
objects.
3. Software triggers
One of the IIO default configfs groups is the "triggers" group. It is
automagically accessible when the configfs is mounted and can be found
under /config/iio/triggers.
IIO software triggers implementation offers support for creating multiple
trigger types. A new trigger type is usually implemented as a separate
kernel module following the interface in include/linux/iio/sw_trigger.h:
/*
* drivers/iio/trigger/iio-trig-sample.c
* sample kernel module implementing a new trigger type
*/
#include <linux/iio/sw_trigger.h>
static struct iio_sw_trigger *iio_trig_sample_probe(const char *name)
{
/*
* This allocates and registers an IIO trigger plus other
* trigger type specific initialization.
*/
}
static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
{
/*
* This undoes the actions in iio_trig_sample_probe
*/
}
static const struct iio_sw_trigger_ops iio_trig_sample_ops = {
.probe = iio_trig_sample_probe,
.remove = iio_trig_sample_remove,
};
static struct iio_sw_trigger_type iio_trig_sample = {
.name = "trig-sample",
.owner = THIS_MODULE,
.ops = &iio_trig_sample_ops,
};
module_iio_sw_trigger_driver(iio_trig_sample);
Each trigger type has its own directory under /config/iio/triggers. Loading
iio-trig-sample module will create 'trig-sample' trigger type directory
/config/iio/triggers/trig-sample.
We support the following interrupt sources (trigger types):
* hrtimer, uses high resolution timers as interrupt source
3.1 Hrtimer triggers creation and destruction
Loading iio-trig-hrtimer module will register hrtimer trigger types allowing
users to create hrtimer triggers under /config/iio/triggers/hrtimer.
e.g:
$ mkdir /config/triggers/hrtimer/instance1
$ rmdir /config/triggers/hrtimer/instance1
Each trigger can have one or more attributes specific to the trigger type.
3.2 "hrtimer" trigger types attributes
"hrtimer" trigger type doesn't have any configurable attribute from /config dir.
It does introduce the sampling_frequency attribute to trigger directory.
......@@ -22,6 +22,14 @@ if IIO_BUFFER
source "drivers/iio/buffer/Kconfig"
endif # IIO_BUFFER
config IIO_CONFIGFS
tristate "Enable IIO configuration via configfs"
select CONFIGFS_FS
help
This allows configuring various IIO bits through configfs
(e.g. software triggers). For more info see
Documentation/iio/iio_configfs.txt.
config IIO_TRIGGER
bool "Enable triggered sampling support"
help
......@@ -38,6 +46,14 @@ config IIO_CONSUMERS_PER_TRIGGER
This value controls the maximum number of consumers that a
given trigger may handle. Default is 2.
config IIO_SW_TRIGGER
tristate "Enable software triggers support"
select IIO_CONFIGFS
help
Provides IIO core support for software triggers. A software
trigger can be created via configfs or directly by a driver
using the API provided.
config IIO_TRIGGERED_EVENT
tristate
select IIO_TRIGGER
......@@ -53,6 +69,7 @@ source "drivers/iio/dac/Kconfig"
source "drivers/iio/dummy/Kconfig"
source "drivers/iio/frequency/Kconfig"
source "drivers/iio/gyro/Kconfig"
source "drivers/iio/health/Kconfig"
source "drivers/iio/humidity/Kconfig"
source "drivers/iio/imu/Kconfig"
source "drivers/iio/light/Kconfig"
......
......@@ -7,6 +7,8 @@ industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
obj-$(CONFIG_IIO_SW_TRIGGER) += industrialio-sw-trigger.o
obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o
obj-y += accel/
......@@ -19,6 +21,7 @@ obj-y += dac/
obj-y += dummy/
obj-y += gyro/
obj-y += frequency/
obj-y += health/
obj-y += humidity/
obj-y += imu/
obj-y += light/
......
......@@ -194,6 +194,25 @@ config HI8435
This driver can also be built as a module. If so, the module will be
called hi8435.
config INA2XX_ADC
tristate "Texas Instruments INA2xx Power Monitors IIO driver"
depends on I2C && !SENSORS_INA2XX
select REGMAP_I2C
select IIO_BUFFER
select IIO_KFIFO_BUF
help
Say yes here to build support for TI INA2xx family of Power Monitors.
This driver is mutually exclusive with the HWMON version.
config IMX7D_ADC
tristate "IMX7D ADC driver"
depends on ARCH_MXC || COMPILE_TEST
help
Say yes here to build support for IMX7D ADC.
This driver can also be built as a module. If so, the module will be
called imx7d_adc.
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
......@@ -332,11 +351,11 @@ config TI_ADC081C
called ti-adc081c.
config TI_ADC128S052
tristate "Texas Instruments ADC128S052/ADC122S021"
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI
help
If you say yes here you get support for Texas Instruments ADC128S052
and ADC122S021 chips.
If you say yes here you get support for Texas Instruments ADC128S052,
ADC122S021 and ADC124S021 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
......
......@@ -20,6 +20,8 @@ obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
......
This diff is collapsed.
This diff is collapsed.
......@@ -305,6 +305,10 @@ static const struct attribute_group mcp3422_attribute_group = {
.attrs = mcp3422_attributes,
};
static const struct iio_chan_spec mcp3421_channels[] = {
MCP3422_CHAN(0),
};
static const struct iio_chan_spec mcp3422_channels[] = {
MCP3422_CHAN(0),
MCP3422_CHAN(1),
......@@ -352,6 +356,10 @@ static int mcp3422_probe(struct i2c_client *client,
indio_dev->info = &mcp3422_info;
switch (adc->id) {
case 1:
indio_dev->channels = mcp3421_channels;
indio_dev->num_channels = ARRAY_SIZE(mcp3421_channels);
break;
case 2:
case 3:
case 6:
......@@ -383,6 +391,7 @@ static int mcp3422_probe(struct i2c_client *client,
}
static const struct i2c_device_id mcp3422_id[] = {
{ "mcp3421", 1 },
{ "mcp3422", 2 },
{ "mcp3423", 3 },
{ "mcp3424", 4 },
......
/*
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
* Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip.
* Driver for Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip.
* Datasheets can be found here:
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
* http://www.ti.com/lit/ds/symlink/adc122s021.pdf
* http://www.ti.com/lit/ds/symlink/adc124s021.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
......@@ -114,9 +115,17 @@ static const struct iio_chan_spec adc122s021_channels[] = {
ADC128_VOLTAGE_CHANNEL(1),
};
static const struct iio_chan_spec adc124s021_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
ADC128_VOLTAGE_CHANNEL(2),
ADC128_VOLTAGE_CHANNEL(3),
};
static const struct adc128_configuration adc128_config[] = {
{ adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
{ adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
{ adc124s021_channels, ARRAY_SIZE(adc124s021_channels) },
};
static const struct iio_info adc128_info = {
......@@ -177,6 +186,7 @@ static int adc128_remove(struct spi_device *spi)
static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc128s052", },
{ .compatible = "ti,adc122s021", },
{ .compatible = "ti,adc124s021", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
......@@ -184,6 +194,7 @@ MODULE_DEVICE_TABLE(of, adc128_of_match);
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0}, /* index into adc128_config */
{ "adc122s021", 1},
{ "adc124s021", 2},
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);
......
......@@ -4,6 +4,14 @@
menu "Chemical Sensors"
config IAQCORE
tristate "AMS iAQ-Core VOC sensors"
depends on I2C
help
Say Y here to build I2C interface support for the AMS
iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
sensors
config VZ89X
tristate "SGX Sensortech MiCS VZ89X VOC sensor"
depends on I2C
......
......@@ -3,4 +3,5 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_VZ89X) += vz89x.o
/*
* ams-iaq-core.c - Support for AMS iAQ-Core VOC sensors
*
* Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#define AMS_IAQCORE_DATA_SIZE 9
#define AMS_IAQCORE_VOC_CO2_IDX 0
#define AMS_IAQCORE_VOC_RESISTANCE_IDX 1
#define AMS_IAQCORE_VOC_TVOC_IDX 2
struct ams_iaqcore_reading {
__be16 co2_ppm;
u8 status;
__be32 resistance;
__be16 voc_ppb;
} __attribute__((__packed__));
struct ams_iaqcore_data {
struct i2c_client *client;
struct mutex lock;
unsigned long last_update;
struct ams_iaqcore_reading buffer;
};
static const struct iio_chan_spec ams_iaqcore_channels[] = {
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_CO2,
.modified = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AMS_IAQCORE_VOC_CO2_IDX,
},
{
.type = IIO_RESISTANCE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AMS_IAQCORE_VOC_RESISTANCE_IDX,
},
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_VOC,
.modified = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AMS_IAQCORE_VOC_TVOC_IDX,
},
};
static int ams_iaqcore_read_measurement(struct ams_iaqcore_data *data)
{
struct i2c_client *client = data->client;
int ret;
struct i2c_msg msg = {
.addr = client->addr,
.flags = client->flags | I2C_M_RD,
.len = AMS_IAQCORE_DATA_SIZE,
.buf = (char *) &data->buffer,
};
ret = i2c_transfer(client->adapter, &msg, 1);
return (ret == AMS_IAQCORE_DATA_SIZE) ? 0 : ret;
}
static int ams_iaqcore_get_measurement(struct ams_iaqcore_data *data)
{
int ret;
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 0;
ret = ams_iaqcore_read_measurement(data);
if (ret < 0)
return ret;
data->last_update = jiffies;
return 0;
}
static int ams_iaqcore_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct ams_iaqcore_data *data = iio_priv(indio_dev);
int ret;
if (mask != IIO_CHAN_INFO_PROCESSED)
return -EINVAL;
mutex_lock(&data->lock);
ret = ams_iaqcore_get_measurement(data);
if (ret)
goto err_out;
switch (chan->address) {
case AMS_IAQCORE_VOC_CO2_IDX:
*val = 0;
*val2 = be16_to_cpu(data->buffer.co2_ppm);
ret = IIO_VAL_INT_PLUS_MICRO;
break;
case AMS_IAQCORE_VOC_RESISTANCE_IDX:
*val = be32_to_cpu(data->buffer.resistance);
ret = IIO_VAL_INT;
break;
case AMS_IAQCORE_VOC_TVOC_IDX:
*val = 0;
*val2 = be16_to_cpu(data->buffer.voc_ppb);
ret = IIO_VAL_INT_PLUS_NANO;
break;
default:
ret = -EINVAL;
}
err_out:
mutex_unlock(&data->lock);
return ret;
}
static const struct iio_info ams_iaqcore_info = {
.read_raw = ams_iaqcore_read_raw,
.driver_module = THIS_MODULE,
};
static int ams_iaqcore_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct ams_iaqcore_data *data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
/* so initial reading will complete */
data->last_update = jiffies - HZ;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &ams_iaqcore_info,
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ams_iaqcore_channels;
indio_dev->num_channels = ARRAY_SIZE(ams_iaqcore_channels);
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ams_iaqcore_id[] = {
{ "ams-iaq-core", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ams_iaqcore_id);
static const struct of_device_id ams_iaqcore_dt_ids[] = {
{ .compatible = "ams,iaq-core" },
{ }
};
MODULE_DEVICE_TABLE(of, ams_iaqcore_dt_ids);
static struct i2c_driver ams_iaqcore_driver = {
.driver = {
.name = "ams-iaq-core",
.of_match_table = of_match_ptr(ams_iaqcore_dt_ids),
},
.probe = ams_iaqcore_probe,
.id_table = ams_iaqcore_id,
};
module_i2c_driver(ams_iaqcore_driver);
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
MODULE_DESCRIPTION("AMS iAQ-Core VOC sensors");
MODULE_LICENSE("GPL v2");
......@@ -34,8 +34,9 @@
struct vz89x_data {
struct i2c_client *client;
struct mutex lock;
unsigned long last_update;
int (*xfer)(struct vz89x_data *data, u8 cmd);
unsigned long last_update;
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
};
......@@ -100,27 +101,60 @@ static int vz89x_measurement_is_valid(struct vz89x_data *data)
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
}
static int vz89x_get_measurement(struct vz89x_data *data)
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{
struct i2c_client *client = data->client;
struct i2c_msg msg[2];
int ret;
int i;
u8 buf[3] = { cmd, 0, 0};
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 0;
msg[0].addr = client->addr;
msg[0].flags = client->flags;
msg[0].len = 3;
msg[0].buf = (char *) &buf;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
msg[1].buf = (char *) &data->buffer;
ret = i2c_transfer(client->adapter, msg, 2);
ret = i2c_smbus_write_word_data(data->client,
VZ89X_REG_MEASUREMENT, 0);
return (ret == 2) ? 0 : ret;
}
static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
{
struct i2c_client *client = data->client;
int ret;
int i;
ret = i2c_smbus_write_word_data(client, cmd, 0);
if (ret < 0)
return ret;
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
ret = i2c_smbus_read_byte(data->client);
ret = i2c_smbus_read_byte(client);
if (ret < 0)
return ret;
data->buffer[i] = ret;
}
return 0;
}
static int vz89x_get_measurement(struct vz89x_data *data)
{
int ret;
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 0;
ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
if (ret < 0)
return ret;
ret = vz89x_measurement_is_valid(data);
if (ret)
return -EAGAIN;
......@@ -204,15 +238,19 @@ static int vz89x_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
struct vz89x_data *data;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BYTE))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
data->xfer = vz89x_i2c_xfer;
else if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
data->xfer = vz89x_smbus_xfer;
else
return -ENOTSUPP;
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->last_update = jiffies - HZ;
......
......@@ -18,9 +18,6 @@
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
#define ST_SENSORS_WAI_ADDRESS 0x0f
static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
{
return (s32)((p[0] | p[1] << 8 | p[2] << 16) << 8) >> 8;
......
......@@ -5,7 +5,8 @@ menu "IIO dummy driver"
depends on IIO
config IIO_DUMMY_EVGEN
tristate
select IRQ_WORK
tristate
config IIO_SIMPLE_DUMMY
tristate "An example driver with no hardware requirements"
......
#
# Health sensors
#
# When adding new entries keep the list in alphabetical order
menu "Health sensors"
config MAX30100
tristate "MAX30100 heart rate and pulse oximeter sensor"
depends on I2C
select REGMAP_I2C
select IIO_BUFFER
select IIO_KFIFO_BUF
help
Say Y here to build I2C interface support for the Maxim
MAX30100 heart rate, and pulse oximeter sensor.
To compile this driver as a module, choose M here: the
module will be called max30100.
endmenu
#
# Makefile for IIO Health sensors
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_MAX30100) += max30100.o
This diff is collapsed.
/*
* Industrial I/O configfs bits
*
* Copyright (c) 2015 Intel Corporation
*
* 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/configfs.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/iio/configfs.h>
static struct config_item_type iio_root_group_type = {
.ct_owner = THIS_MODULE,
};
struct configfs_subsystem iio_configfs_subsys = {
.su_group = {
.cg_item = {
.ci_namebuf = "iio",
.ci_type = &iio_root_group_type,
},
},
.su_mutex = __MUTEX_INITIALIZER(iio_configfs_subsys.su_mutex),
};
EXPORT_SYMBOL(iio_configfs_subsys);
static int __init iio_configfs_init(void)
{
config_group_init(&iio_configfs_subsys.su_group);
return configfs_register_subsystem(&iio_configfs_subsys);
}
module_init(iio_configfs_init);
static void __exit iio_configfs_exit(void)
{
configfs_unregister_subsystem(&iio_configfs_subsys);
}
module_exit(iio_configfs_exit);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("Industrial I/O configfs support");
MODULE_LICENSE("GPL v2");
/*
* The Industrial I/O core, software trigger functions
*
* Copyright (c) 2015 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/iio/sw_trigger.h>
#include <linux/iio/configfs.h>
#include <linux/configfs.h>
static struct config_group *iio_triggers_group;
static struct config_item_type iio_trigger_type_group_type;
static struct config_item_type iio_triggers_group_type = {
.ct_owner = THIS_MODULE,
};
static LIST_HEAD(iio_trigger_types_list);
static DEFINE_MUTEX(iio_trigger_types_lock);
static
struct iio_sw_trigger_type *__iio_find_sw_trigger_type(const char *name,
unsigned len)
{
struct iio_sw_trigger_type *t = NULL, *iter;
list_for_each_entry(iter, &iio_trigger_types_list, list)
if (!strcmp(iter->name, name)) {
t = iter;
break;
}
return t;
}
int iio_register_sw_trigger_type(struct iio_sw_trigger_type *t)
{
struct iio_sw_trigger_type *iter;
int ret = 0;
mutex_lock(&iio_trigger_types_lock);
iter = __iio_find_sw_trigger_type(t->name, strlen(t->name));
if (iter)
ret = -EBUSY;
else
list_add_tail(&t->list, &iio_trigger_types_list);
mutex_unlock(&iio_trigger_types_lock);
if (ret)
return ret;
t->group = configfs_register_default_group(iio_triggers_group, t->name,
&iio_trigger_type_group_type);
if (IS_ERR(t->group))
ret = PTR_ERR(t->group);
return ret;
}
EXPORT_SYMBOL(iio_register_sw_trigger_type);
void iio_unregister_sw_trigger_type(struct iio_sw_trigger_type *t)
{
struct iio_sw_trigger_type *iter;
mutex_lock(&iio_trigger_types_lock);
iter = __iio_find_sw_trigger_type(t->name, strlen(t->name));
if (iter)
list_del(&t->list);
mutex_unlock(&iio_trigger_types_lock);
configfs_unregister_default_group(t->group);
}
EXPORT_SYMBOL(iio_unregister_sw_trigger_type);
static
struct iio_sw_trigger_type *iio_get_sw_trigger_type(const char *name)
{
struct iio_sw_trigger_type *t;
mutex_lock(&iio_trigger_types_lock);
t = __iio_find_sw_trigger_type(name, strlen(name));
if (t && !try_module_get(t->owner))
t = NULL;
mutex_unlock(&iio_trigger_types_lock);
return t;
}
struct iio_sw_trigger *iio_sw_trigger_create(const char *type, const char *name)
{
struct iio_sw_trigger *t;
struct iio_sw_trigger_type *tt;
tt = iio_get_sw_trigger_type(type);
if (!tt) {
pr_err("Invalid trigger type: %s\n", type);
return ERR_PTR(-EINVAL);
}
t = tt->ops->probe(name);
if (IS_ERR(t))
goto out_module_put;
t->trigger_type = tt;
return t;
out_module_put:
module_put(tt->owner);
return t;
}
EXPORT_SYMBOL(iio_sw_trigger_create);
void iio_sw_trigger_destroy(struct iio_sw_trigger *t)
{
struct iio_sw_trigger_type *tt = t->trigger_type;
tt->ops->remove(t);
module_put(tt->owner);
}
EXPORT_SYMBOL(iio_sw_trigger_destroy);
static struct config_group *trigger_make_group(struct config_group *group,
const char *name)
{
struct iio_sw_trigger *t;
t = iio_sw_trigger_create(group->cg_item.ci_name, name);
if (IS_ERR(t))
return ERR_CAST(t);
config_item_set_name(&t->group.cg_item, "%s", name);
return &t->group;
}
static void trigger_drop_group(struct config_group *group,
struct config_item *item)
{
struct iio_sw_trigger *t = to_iio_sw_trigger(item);
iio_sw_trigger_destroy(t);
config_item_put(item);
}
static struct configfs_group_operations trigger_ops = {
.make_group = &trigger_make_group,
.drop_item = &trigger_drop_group,
};
static struct config_item_type iio_trigger_type_group_type = {
.ct_group_ops = &trigger_ops,
.ct_owner = THIS_MODULE,
};
static int __init iio_sw_trigger_init(void)
{
iio_triggers_group =
configfs_register_default_group(&iio_configfs_subsys.su_group,
"triggers",
&iio_triggers_group_type);
if (IS_ERR(iio_triggers_group))
return PTR_ERR(iio_triggers_group);
return 0;
}
module_init(iio_sw_trigger_init);
static void __exit iio_sw_trigger_exit(void)
{
configfs_unregister_default_group(iio_triggers_group);
}
module_exit(iio_sw_trigger_exit);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("Industrial I/O software triggers support");
MODULE_LICENSE("GPL v2");
......@@ -61,12 +61,10 @@ EXPORT_SYMBOL_GPL(iio_map_array_register);
int iio_map_array_unregister(struct iio_dev *indio_dev)
{
int ret = -ENODEV;
struct iio_map_internal *mapi;
struct list_head *pos, *tmp;
struct iio_map_internal *mapi, *next;
mutex_lock(&iio_map_list_lock);
list_for_each_safe(pos, tmp, &iio_map_list) {
mapi = list_entry(pos, struct iio_map_internal, l);
list_for_each_entry_safe(mapi, next, &iio_map_list, l) {
if (indio_dev == mapi->indio_dev) {
list_del(&mapi->l);
kfree(mapi);
......
......@@ -23,6 +23,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#define US5182D_REG_CFG0 0x00
#define US5182D_CFG0_ONESHOT_EN BIT(6)
......@@ -81,6 +83,7 @@
#define US5182D_READ_BYTE 1
#define US5182D_READ_WORD 2
#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */
#define US5182D_SLEEP_MS 3000 /* ms */
/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,
......@@ -99,6 +102,11 @@ enum mode {
US5182D_PX_ONLY
};
enum pmode {
US5182D_CONTINUOUS,
US5182D_ONESHOT
};
struct us5182d_data {
struct i2c_client *client;
struct mutex lock;
......@@ -112,6 +120,12 @@ struct us5182d_data {
u16 *us5182d_dark_ths;
u8 opmode;
u8 power_mode;
bool als_enabled;
bool px_enabled;
bool default_continuous;
};
static IIO_CONST_ATTR(in_illuminance_scale_available,
......@@ -130,13 +144,11 @@ static const struct {
u8 reg;
u8 val;
} us5182d_regvals[] = {
{US5182D_REG_CFG0, (US5182D_CFG0_SHUTDOWN_EN |
US5182D_CFG0_WORD_ENABLE)},
{US5182D_REG_CFG0, US5182D_CFG0_WORD_ENABLE},
{US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
{US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
US5182D_CFG2_PXGAIN_DEFAULT)},
{US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100},
{US5182D_REG_MODE_STORE, US5182D_STORE_MODE},
{US5182D_REG_CFG4, 0x00},
};
......@@ -169,7 +181,7 @@ static int us5182d_get_als(struct us5182d_data *data)
return result;
}
static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
static int us5182d_oneshot_en(struct us5182d_data *data)
{
int ret;
......@@ -183,6 +195,20 @@ static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
*/
ret = ret | US5182D_CFG0_ONESHOT_EN;
return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
}
static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
{
int ret;
if (mode == data->opmode)
return 0;
ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
if (ret < 0)
return ret;
/* update mode */
ret = ret & ~US5182D_OPMODE_MASK;
ret = ret | (mode << US5182D_OPMODE_SHIFT);
......@@ -196,9 +222,6 @@ static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
if (ret < 0)
return ret;
if (mode == data->opmode)
return 0;
ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,
US5182D_STORE_MODE);
if (ret < 0)
......@@ -210,6 +233,96 @@ static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)
return 0;
}
static int us5182d_als_enable(struct us5182d_data *data)
{
int ret;
u8 mode;
if (data->power_mode == US5182D_ONESHOT)
return us5182d_set_opmode(data, US5182D_ALS_ONLY);
if (data->als_enabled)
return 0;
mode = data->px_enabled ? US5182D_ALS_PX : US5182D_ALS_ONLY;
ret = us5182d_set_opmode(data, mode);
if (ret < 0)
return ret;
data->als_enabled = true;
return 0;
}
static int us5182d_px_enable(struct us5182d_data *data)
{
int ret;
u8 mode;
if (data->power_mode == US5182D_ONESHOT)
return us5182d_set_opmode(data, US5182D_PX_ONLY);
if (data->px_enabled)
return 0;
mode = data->als_enabled ? US5182D_ALS_PX : US5182D_PX_ONLY;
ret = us5182d_set_opmode(data, mode);
if (ret < 0)
return ret;
data->px_enabled = true;
return 0;
}
static int us5182d_shutdown_en(struct us5182d_data *data, u8 state)
{
int ret;
if (data->power_mode == US5182D_ONESHOT)
return 0;
ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
if (ret < 0)
return ret;
ret = ret & ~US5182D_CFG0_SHUTDOWN_EN;
ret = ret | state;
ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);
if (ret < 0)
return ret;
if (state & US5182D_CFG0_SHUTDOWN_EN) {
data->als_enabled = false;
data->px_enabled = false;
}
return ret;
}
static int us5182d_set_power_state(struct us5182d_data *data, bool on)
{
int ret;
if (data->power_mode == US5182D_ONESHOT)
return 0;
if (on) {
ret = pm_runtime_get_sync(&data->client->dev);
if (ret < 0)
pm_runtime_put_noidle(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
}
return ret;
}
static int us5182d_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
......@@ -222,29 +335,49 @@ static int us5182d_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_LIGHT:
mutex_lock(&data->lock);
ret = us5182d_set_opmode(data, US5182D_OPMODE_ALS);
if (data->power_mode == US5182D_ONESHOT) {
ret = us5182d_oneshot_en(data);
if (ret < 0)
goto out_err;
}
ret = us5182d_set_power_state(data, true);
if (ret < 0)
goto out_err;
ret = us5182d_als_enable(data);
if (ret < 0)
goto out_poweroff;
ret = us5182d_get_als(data);
if (ret < 0)
goto out_poweroff;
*val = ret;
ret = us5182d_set_power_state(data, false);
if (ret < 0)
goto out_err;
mutex_unlock(&data->lock);
*val = ret;
return IIO_VAL_INT;
case IIO_PROXIMITY:
mutex_lock(&data->lock);
ret = us5182d_set_opmode(data, US5182D_OPMODE_PX);
if (data->power_mode == US5182D_ONESHOT) {
ret = us5182d_oneshot_en(data);
if (ret < 0)
goto out_err;
}
ret = us5182d_set_power_state(data, true);
if (ret < 0)
goto out_err;
ret = us5182d_px_enable(data);
if (ret < 0)
goto out_poweroff;
ret = i2c_smbus_read_word_data(data->client,
US5182D_REG_PDL);
if (ret < 0)
goto out_poweroff;
*val = ret;
ret = us5182d_set_power_state(data, false);
if (ret < 0)
goto out_err;
mutex_unlock(&data->lock);
*val = ret;
return IIO_VAL_INT;
return IIO_VAL_INT;
default:
return -EINVAL;
}
......@@ -263,6 +396,9 @@ static int us5182d_read_raw(struct iio_dev *indio_dev,
}
return -EINVAL;
out_poweroff:
us5182d_set_power_state(data, false);
out_err:
mutex_unlock(&data->lock);
return ret;
......@@ -368,6 +504,7 @@ static int us5182d_init(struct iio_dev *indio_dev)
return ret;
data->opmode = 0;
data->power_mode = US5182D_CONTINUOUS;
for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
ret = i2c_smbus_write_byte_data(data->client,
us5182d_regvals[i].reg,
......@@ -376,7 +513,17 @@ static int us5182d_init(struct iio_dev *indio_dev)
return ret;
}
return 0;
data->als_enabled = true;
data->px_enabled = true;
if (!data->default_continuous) {
ret = us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
if (ret < 0)
return ret;
data->power_mode = US5182D_ONESHOT;
}
return ret;
}
static void us5182d_get_platform_data(struct iio_dev *indio_dev)
......@@ -399,6 +546,8 @@ static void us5182d_get_platform_data(struct iio_dev *indio_dev)
"upisemi,lower-dark-gain",
&data->lower_dark_gain))
data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;
data->default_continuous = device_property_read_bool(&data->client->dev,
"upisemi,continuous");
}
static int us5182d_dark_gain_config(struct iio_dev *indio_dev)
......@@ -464,18 +613,73 @@ static int us5182d_probe(struct i2c_client *client,
ret = us5182d_dark_gain_config(indio_dev);
if (ret < 0)
return ret;
goto out_err;
if (data->default_continuous) {
pm_runtime_set_active(&client->dev);
if (ret < 0)
goto out_err;
}
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev,
US5182D_SLEEP_MS);
pm_runtime_use_autosuspend(&client->dev);
ret = iio_device_register(indio_dev);
if (ret < 0)
goto out_err;
return 0;
out_err:
us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
return ret;
return iio_device_register(indio_dev);
}
static int us5182d_remove(struct i2c_client *client)
{
struct us5182d_data *data = iio_priv(i2c_get_clientdata(client));
iio_device_unregister(i2c_get_clientdata(client));
return i2c_smbus_write_byte_data(client, US5182D_REG_CFG0,
US5182D_CFG0_SHUTDOWN_EN);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
}
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
static int us5182d_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct us5182d_data *data = iio_priv(indio_dev);
if (data->power_mode == US5182D_CONTINUOUS)
return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
return 0;
}
static int us5182d_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct us5182d_data *data = iio_priv(indio_dev);
if (data->power_mode == US5182D_CONTINUOUS)
return us5182d_shutdown_en(data,
~US5182D_CFG0_SHUTDOWN_EN & 0xff);
return 0;
}
#endif
static const struct dev_pm_ops us5182d_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(us5182d_suspend, us5182d_resume)
SET_RUNTIME_PM_OPS(us5182d_suspend, us5182d_resume, NULL)
};
static const struct acpi_device_id us5182d_acpi_match[] = {
{ "USD5182", 0},
{}
......@@ -493,6 +697,7 @@ MODULE_DEVICE_TABLE(i2c, us5182d_id);
static struct i2c_driver us5182d_driver = {
.driver = {
.name = US5182D_DRV_NAME,
.pm = &us5182d_pm_ops,
.acpi_match_table = ACPI_PTR(us5182d_acpi_match),
},
.probe = us5182d_probe,
......
......@@ -36,8 +36,10 @@
#define LIDAR_REG_STATUS_INVALID BIT(3)
#define LIDAR_REG_STATUS_READY BIT(0)
#define LIDAR_REG_DATA_HBYTE 0x0f
#define LIDAR_REG_DATA_LBYTE 0x10
#define LIDAR_REG_DATA_HBYTE 0x0f
#define LIDAR_REG_DATA_LBYTE 0x10
#define LIDAR_REG_DATA_WORD_READ BIT(7)
#define LIDAR_REG_PWR_CONTROL 0x65
#define LIDAR_DRV_NAME "lidar"
......@@ -46,6 +48,9 @@ struct lidar_data {
struct iio_dev *indio_dev;
struct i2c_client *client;
int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
int i2c_enabled;
u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
};
......@@ -64,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int lidar_read_byte(struct lidar_data *data, int reg)
static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
{
struct i2c_client *client = data->client;
struct i2c_msg msg[2];
int ret;
msg[0].addr = client->addr;
msg[0].flags = client->flags | I2C_M_STOP;
msg[0].len = 1;
msg[0].buf = (char *) &reg;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = len;
msg[1].buf = (char *) val;
ret = i2c_transfer(client->adapter, msg, 2);
return (ret == 2) ? 0 : ret;
}
static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
{
struct i2c_client *client = data->client;
int ret;
......@@ -74,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg)
* so in turn i2c_smbus_read_byte_data cannot be used
*/
ret = i2c_smbus_write_byte(client, reg);
if (ret < 0) {
dev_err(&client->dev, "cannot write addr value");
return ret;
while (len--) {
ret = i2c_smbus_write_byte(client, reg++);
if (ret < 0) {
dev_err(&client->dev, "cannot write addr value");
return ret;
}
ret = i2c_smbus_read_byte(client);
if (ret < 0) {
dev_err(&client->dev, "cannot read data value");
return ret;
}
*(val++) = ret;
}
ret = i2c_smbus_read_byte(client);
return 0;
}
static int lidar_read_byte(struct lidar_data *data, u8 reg)
{
int ret;
u8 val;
ret = data->xfer(data, reg, &val, 1);
if (ret < 0)
dev_err(&client->dev, "cannot read data value");
return ret;
return ret;
return val;
}
static inline int lidar_write_control(struct lidar_data *data, int val)
......@@ -100,22 +144,14 @@ static inline int lidar_write_power(struct lidar_data *data, int val)
static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
{
int ret;
int val;
ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
if (ret < 0)
return ret;
val = ret << 8;
int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
(data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
(u8 *) reg, 2);
ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
if (ret < 0)
return ret;
if (!ret)
*reg = be16_to_cpu(*reg);
val |= ret;
*reg = val;
return 0;
return ret;
}
static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
......@@ -233,6 +269,16 @@ static int lidar_probe(struct i2c_client *client,
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
data->xfer = lidar_i2c_xfer;
data->i2c_enabled = 1;
} else if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
data->xfer = lidar_smbus_xfer;
else
return -ENOTSUPP;
indio_dev->info = &lidar_info;
indio_dev->name = LIDAR_DRV_NAME;
......@@ -240,7 +286,6 @@ static int lidar_probe(struct i2c_client *client,
indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
......
......@@ -5,6 +5,16 @@
menu "Triggers - standalone"
config IIO_HRTIMER_TRIGGER
tristate "High resolution timer trigger"
depends on IIO_SW_TRIGGER
help
Provides a frequency based IIO trigger using high resolution
timers as interrupt source.
To compile this driver as a module, choose M here: the
module will be called iio-trig-hrtimer.
config IIO_INTERRUPT_TRIGGER
tristate "Generic interrupt trigger"
help
......
......@@ -3,5 +3,7 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
/**
* The industrial I/O periodic hrtimer trigger driver
*
* Copyright (C) Intuitive Aerial AB
* Written by Marten Svanfeldt, marten@intuitiveaerial.com
* Copyright (C) 2012, Analog Device Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
* Copyright (C) 2015, Intel Corporation
*
* 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/slab.h>
#include <linux/hrtimer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/sw_trigger.h>
/* default sampling frequency - 100Hz */
#define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100
struct iio_hrtimer_info {
struct iio_sw_trigger swt;
struct hrtimer timer;
unsigned long sampling_frequency;
ktime_t period;
};
static struct config_item_type iio_hrtimer_type = {
.ct_owner = THIS_MODULE,
};
static
ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_trigger *trig = to_iio_trigger(dev);
struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
return snprintf(buf, PAGE_SIZE, "%lu\n", info->sampling_frequency);
}
static
ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_trigger *trig = to_iio_trigger(dev);
struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig);
unsigned long val;
int ret;
ret = kstrtoul(buf, 10, &val);
if (ret)
return ret;
if (!val || val > NSEC_PER_SEC)
return -EINVAL;
info->sampling_frequency = val;
info->period = ktime_set(0, NSEC_PER_SEC / val);
return len;
}
static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR,
iio_hrtimer_show_sampling_frequency,
iio_hrtimer_store_sampling_frequency);
static struct attribute *iio_hrtimer_attrs[] = {
&dev_attr_sampling_frequency.attr,
NULL
};
static const struct attribute_group iio_hrtimer_attr_group = {
.attrs = iio_hrtimer_attrs,
};
static const struct attribute_group *iio_hrtimer_attr_groups[] = {
&iio_hrtimer_attr_group,
NULL
};
static enum hrtimer_restart iio_hrtimer_trig_handler(struct hrtimer *timer)
{
struct iio_hrtimer_info *info;
info = container_of(timer, struct iio_hrtimer_info, timer);
hrtimer_forward_now(timer, info->period);
iio_trigger_poll(info->swt.trigger);
return HRTIMER_RESTART;
}
static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state)
{
struct iio_hrtimer_info *trig_info;
trig_info = iio_trigger_get_drvdata(trig);
if (state)
hrtimer_start(&trig_info->timer, trig_info->period,
HRTIMER_MODE_REL);
else
hrtimer_cancel(&trig_info->timer);
return 0;
}
static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = iio_trig_hrtimer_set_state,
};
static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name)
{
struct iio_hrtimer_info *trig_info;
int ret;
trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
if (!trig_info)
return ERR_PTR(-ENOMEM);
trig_info->swt.trigger = iio_trigger_alloc("%s", name);
if (!trig_info->swt.trigger) {
ret = -ENOMEM;
goto err_free_trig_info;
}
iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info);
trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops;
trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups;
hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
trig_info->timer.function = iio_hrtimer_trig_handler;
trig_info->sampling_frequency = HRTIMER_DEFAULT_SAMPLING_FREQUENCY;
trig_info->period = ktime_set(0, NSEC_PER_SEC /
trig_info->sampling_frequency);
ret = iio_trigger_register(trig_info->swt.trigger);
if (ret)
goto err_free_trigger;
iio_swt_group_init_type_name(&trig_info->swt, name, &iio_hrtimer_type);
return &trig_info->swt;
err_free_trigger:
iio_trigger_free(trig_info->swt.trigger);
err_free_trig_info:
kfree(trig_info);
return ERR_PTR(ret);
}
static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt)
{
struct iio_hrtimer_info *trig_info;
trig_info = iio_trigger_get_drvdata(swt->trigger);
iio_trigger_unregister(swt->trigger);
/* cancel the timer after unreg to make sure no one rearms it */
hrtimer_cancel(&trig_info->timer);
iio_trigger_free(swt->trigger);
kfree(trig_info);
return 0;
}
static const struct iio_sw_trigger_ops iio_trig_hrtimer_ops = {
.probe = iio_trig_hrtimer_probe,
.remove = iio_trig_hrtimer_remove,
};
static struct iio_sw_trigger_type iio_trig_hrtimer = {
.name = "hrtimer",
.owner = THIS_MODULE,
.ops = &iio_trig_hrtimer_ops,
};
module_iio_sw_trigger_driver(iio_trig_hrtimer);
MODULE_AUTHOR("Marten Svanfeldt <marten@intuitiveaerial.com>");
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("Periodic hrtimer trigger for the IIO subsystem");
MODULE_LICENSE("GPL v2");
......@@ -609,7 +609,7 @@ static const struct iio_chan_spec ad7192_channels[] = {
static int ad7192_probe(struct spi_device *spi)
{
const struct ad7192_platform_data *pdata = spi->dev.platform_data;
const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7192_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
......
......@@ -833,7 +833,7 @@ static const struct ad7280_platform_data ad7793_default_pdata = {
static int ad7280_probe(struct spi_device *spi)
{
const struct ad7280_platform_data *pdata = spi->dev.platform_data;
const struct ad7280_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7280_state *st;
int ret;
const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890};
......
......@@ -345,7 +345,7 @@ static int ad7816_probe(struct spi_device *spi_dev)
{
struct ad7816_chip_info *chip;
struct iio_dev *indio_dev;
unsigned short *pins = spi_dev->dev.platform_data;
unsigned short *pins = dev_get_platdata(&spi_dev->dev);
int ret = 0;
int i;
......
......@@ -201,7 +201,7 @@ static const struct iio_info ad9832_info = {
static int ad9832_probe(struct spi_device *spi)
{
struct ad9832_platform_data *pdata = spi->dev.platform_data;
struct ad9832_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad9832_state *st;
struct regulator *reg;
......
......@@ -318,7 +318,7 @@ static const struct iio_info ad9833_info = {
static int ad9834_probe(struct spi_device *spi)
{
struct ad9834_platform_data *pdata = spi->dev.platform_data;
struct ad9834_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad9834_state *st;
struct iio_dev *indio_dev;
struct regulator *reg;
......
......@@ -1898,7 +1898,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
mutex_init(&chip->prox_mutex);
chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
chip->pdata = clientp->dev.platform_data;
chip->pdata = dev_get_platdata(&clientp->dev);
chip->id = id->driver_data;
chip->chip_info =
&tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
......
/*
* Industrial I/O configfs support
*
* Copyright (c) 2015 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef __IIO_CONFIGFS
#define __IIO_CONFIGFS
extern struct configfs_subsystem iio_configfs_subsys;
#endif /* __IIO_CONFIGFS */
/*
* Industrial I/O software trigger interface
*
* Copyright (c) 2015 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef __IIO_SW_TRIGGER
#define __IIO_SW_TRIGGER
#include <linux/module.h>
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/configfs.h>
#define module_iio_sw_trigger_driver(__iio_sw_trigger_type) \
module_driver(__iio_sw_trigger_type, iio_register_sw_trigger_type, \
iio_unregister_sw_trigger_type)
struct iio_sw_trigger_ops;
struct iio_sw_trigger_type {
const char *name;
struct module *owner;
const struct iio_sw_trigger_ops *ops;
struct list_head list;
struct config_group *group;
};
struct iio_sw_trigger {
struct iio_trigger *trigger;
struct iio_sw_trigger_type *trigger_type;
struct config_group group;
};
struct iio_sw_trigger_ops {
struct iio_sw_trigger* (*probe)(const char *);
int (*remove)(struct iio_sw_trigger *);
};
static inline
struct iio_sw_trigger *to_iio_sw_trigger(struct config_item *item)
{
return container_of(to_config_group(item), struct iio_sw_trigger,
group);
}
int iio_register_sw_trigger_type(struct iio_sw_trigger_type *tt);
void iio_unregister_sw_trigger_type(struct iio_sw_trigger_type *tt);
struct iio_sw_trigger *iio_sw_trigger_create(const char *, const char *);
void iio_sw_trigger_destroy(struct iio_sw_trigger *);
int iio_sw_trigger_type_configfs_register(struct iio_sw_trigger_type *tt);
void iio_sw_trigger_type_configfs_unregister(struct iio_sw_trigger_type *tt);
static inline
void iio_swt_group_init_type_name(struct iio_sw_trigger *t,
const char *name,
struct config_item_type *type)
{
#ifdef CONFIG_CONFIGFS_FS
config_group_init_type_name(&t->group, name, type);
#endif
}
#endif /* __IIO_SW_TRIGGER */
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