summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-12 12:43:41 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-12 12:43:41 -0700
commit1c46ae0af6df0bbde66c5e868563be57f18a27b4 (patch)
treeb5dbe61f8d05f9c67aff0080ea87945342d58c7d
parenta73e99cb67e7438e5ab0c524ae63a8a27616c839 (diff)
parent41d903c00051d8f31c98a8136edbac67e6f8688f (diff)
Merge tag 'iio-for-4.3b-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: Second set of new device support, features and cleanup for the 4.3 cycle. Take 2 also includes a fix set that was too late for the 4.2 cycle. As we had a lot of tools and docs work in this set, I have broken those out into their own categories in this description. Fixes from the pull request '4th set of IIO fixes for the 4.2 cycle'. * Poll functions for both event chardev and the buffer one were returning negative error codes (via a positive value). * A recent change to lsiio adding some error handling that was wrong and stopped the tool working. * bmg160 was missing some dependencies in Kconfig * berlin2-adc had a misshandled register (wrote a value rather than a bitmap) New device support * TI opt3001 light sensor * TXC PA12 ALS and proximity sensor. * mcp3301 ADC support (in mcp320x driver) * ST lsm303agr accelerometer and magnetometer drivers (plus some st-sensors common support to allow different WHOAMI register addresses, devices with fixed scale and allow interrupt equiped magnetometers). * ADIS16305, ADIS16367, ADIS16445IMUs (in the adis16400 driver) * ADIS16266 gyro (in the adis16260 driver) * ADIS16137 gyro (in the adis16136 driver) New functionality * mmc35240 DT bindings. * Inverse unit conversion macros to aid handing of values written to sysfs attributes. Core cleanup * Forward declaration of struct iio_trigger to avoid a compile warning. Driver cleanup / fixes * mxs-lradc - Clarify which parts are supported. - Fix spelling erorrs. - Missing/extra includes - reorder includes - add datasheet name listings for all usable channels (to allow them to be bound by name from consumer drivers) * acpi-als - add some function prefixes as per general iio style. * bmc150_magn - replace a magic value with the existing define. * vf610 - determine possible sample frequencies taking into account the electrical characteristics (defining a minimum sample time) * dht11 - whitespace - additional docs - avoid mulitple assignments in one line - Use the new funciton ktime_get_resolution_ns to cleanup a nasty trick previously used for timing. * Fix all drivers that consider 0 a valid IRQ for historical reasons. * Export I2C module alias info where previously missing (to allow autoprobing) * Export OF module alias info where previously missing. * mmc35240 - switch some variables into arrays to improve readability. * mlx90614 - define some magic numbers for readability. * bmc150_magn - expand area locked by a mutex to cover all the use of the data->buffer. - use descriptive naming for a mask instead of a magic value. * berin2-adc - pass up an error code rather that a generic error - constify the iio_chan_spec - some other little tidy ups. * stk8312 - fix a dependency on triggered buffers in kconfig - add a check for invalid attribute values - improve error handling by returning error codes where possible and return immediately where relevant - rework macro defs to use GENMASK etc - change some variable types to reduce unnecessary casting - clean up code style - drop a local buffer copy for bulk reads and use the one in data->buffer instead. * adis16400 - the adis16448 gyroscope scale was wrong. * adis16480 - some more wrong scales for various parts. * adis16300 - has an undocumented product id and serial number registers so use them. * iio_simple_dummy - fix some wrong code indentation. * bmc150-accel - use the chip ID to detect the chip present rather than verifying the expected part was there. This was in response to a wrong ACPI entry on the WinBook TW100. * mma8452 - fix _get_hp_filter_index - drop a double include - pass up an error code rather than rewriting it - range check input values to attribute writes - register defs tidy up using GENMASK and reordering them to be easier to follow. - various coding style cleanups - put the Kconfig entry in the write place (alphabetically). Tools related * Tools cleanup - drop an explicity NULL comparison, some unnecessary braces, use the ARRAY_SIZE macro, send error messages to stderr instead of dropping them in the middle of normal output. * Fix tools to allow that scale and offset attributes are optional. * More tools fixes including allowing true 32bit data (previously an overflow prevented more than 31bits) * Drop a stray header guard that ended up in a c file. * Make calc_digits static as it isn't exported or in the header. * Set ci_array pointer to NULL after free as a protection against non safe usage of the tools core code. Also convert a double pointer to a single one as the extra level of indirection was unnecessary. Docs * DocBook introduction by Daniel Baluta. Glad we are beginning to draw together some more introductory docs to suplement the various tools / examples. * Drop bytes_per_datum sysfs attribute docs as it no longer exists. * A whole load of missing / fixing of kernel-doc for the core of IIO. * Document the trigger name sysfs attribute in the ABI docs. * Minor typos in the ABI docs related to power down modes.
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio13
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs9
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/iio.tmpl697
-rw-r--r--Documentation/devicetree/bindings/iio/adc/mcp320x.txt1
-rw-r--r--Documentation/devicetree/bindings/iio/adc/vf610-adc.txt5
-rw-r--r--Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt13
-rw-r--r--Documentation/devicetree/bindings/iio/st-sensors.txt2
-rw-r--r--Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt2
-rw-r--r--drivers/iio/accel/Kconfig26
-rw-r--r--drivers/iio/accel/bmc150-accel.c156
-rw-r--r--drivers/iio/accel/kxcjk-1013.c2
-rw-r--r--drivers/iio/accel/mma8452.c217
-rw-r--r--drivers/iio/accel/mma9553.c2
-rw-r--r--drivers/iio/accel/st_accel.h1
-rw-r--r--drivers/iio/accel/st_accel_core.c6
-rw-r--r--drivers/iio/accel/st_accel_i2c.c5
-rw-r--r--drivers/iio/accel/st_accel_spi.c1
-rw-r--r--drivers/iio/accel/stk8312.c107
-rw-r--r--drivers/iio/accel/stk8ba50.c1
-rw-r--r--drivers/iio/adc/Kconfig4
-rw-r--r--drivers/iio/adc/berlin2-adc.c22
-rw-r--r--drivers/iio/adc/mcp320x.c16
-rw-r--r--drivers/iio/adc/vf610_adc.c79
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c52
-rw-r--r--drivers/iio/gyro/Kconfig3
-rw-r--r--drivers/iio/gyro/adis16136.c6
-rw-r--r--drivers/iio/gyro/adis16260.c137
-rw-r--r--drivers/iio/gyro/st_gyro_core.c3
-rw-r--r--drivers/iio/humidity/dht11.c65
-rw-r--r--drivers/iio/imu/adis16400_core.c46
-rw-r--r--drivers/iio/imu/adis16480.c39
-rw-r--r--drivers/iio/imu/kmx61.c8
-rw-r--r--drivers/iio/industrialio-buffer.c17
-rw-r--r--drivers/iio/industrialio-core.c25
-rw-r--r--drivers/iio/industrialio-event.c8
-rw-r--r--drivers/iio/industrialio-trigger.c27
-rw-r--r--drivers/iio/light/Kconfig21
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/acpi-als.c18
-rw-r--r--drivers/iio/light/cm32181.c1
-rw-r--r--drivers/iio/light/cm3232.c1
-rw-r--r--drivers/iio/light/cm36651.c1
-rw-r--r--drivers/iio/light/gp2ap020a00f.c1
-rw-r--r--drivers/iio/light/opt3001.c804
-rw-r--r--drivers/iio/light/pa12203001.c483
-rw-r--r--drivers/iio/light/stk3310.c1
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c24
-rw-r--r--drivers/iio/magnetometer/mmc35240.c33
-rw-r--r--drivers/iio/magnetometer/st_magn.h3
-rw-r--r--drivers/iio/magnetometer/st_magn_buffer.c7
-rw-r--r--drivers/iio/magnetometer/st_magn_core.c98
-rw-r--r--drivers/iio/magnetometer/st_magn_i2c.c5
-rw-r--r--drivers/iio/magnetometer/st_magn_spi.c1
-rw-r--r--drivers/iio/pressure/st_pressure_core.c3
-rw-r--r--drivers/iio/temperature/mlx90614.c20
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c122
-rw-r--r--include/linux/iio/common/st_sensors.h2
-rw-r--r--include/linux/iio/consumer.h2
-rw-r--r--include/linux/iio/iio.h17
-rw-r--r--include/linux/iio/sysfs.h3
-rw-r--r--include/linux/iio/trigger.h3
-rw-r--r--tools/iio/generic_buffer.c48
-rw-r--r--tools/iio/iio_event_monitor.c17
-rw-r--r--tools/iio/iio_utils.c136
-rw-r--r--tools/iio/iio_utils.h4
-rw-r--r--tools/iio/lsiio.c16
67 files changed, 3148 insertions, 574 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index b8753f74af67..42d360fe66a5 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -493,7 +493,7 @@ Contact: linux-iio@vger.kernel.org
Description:
Specifies the output powerdown mode.
DAC output stage is disconnected from the amplifier and
- 1kohm_to_gnd: connected to ground via an 1kOhm resistor,
+ 1kohm_to_gnd: connected to ground via an 1kOhm resistor,
6kohm_to_gnd: connected to ground via a 6kOhm resistor,
20kohm_to_gnd: connected to ground via a 20kOhm resistor,
100kohm_to_gnd: connected to ground via an 100kOhm resistor,
@@ -503,9 +503,9 @@ Description:
outX_powerdown_mode_available. If Y is not present the
mode is shared across all outputs.
-What: /sys/.../iio:deviceX/out_votlageY_powerdown_mode_available
+What: /sys/.../iio:deviceX/out_voltageY_powerdown_mode_available
What: /sys/.../iio:deviceX/out_voltage_powerdown_mode_available
-What: /sys/.../iio:deviceX/out_altvotlageY_powerdown_mode_available
+What: /sys/.../iio:deviceX/out_altvoltageY_powerdown_mode_available
What: /sys/.../iio:deviceX/out_altvoltage_powerdown_mode_available
KernelVersion: 2.6.38
Contact: linux-iio@vger.kernel.org
@@ -1040,13 +1040,6 @@ Contact: linux-iio@vger.kernel.org
Description:
Number of scans contained by the buffer.
-What: /sys/bus/iio/devices/iio:deviceX/buffer/bytes_per_datum
-KernelVersion: 2.6.37
-Contact: linux-iio@vger.kernel.org
-Description:
- Bytes per scan. Due to alignment fun, the scan may be larger
- than implied directly by the scan_element parameters.
-
What: /sys/bus/iio/devices/iio:deviceX/buffer/enable
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs
index 5235e6c749ab..bbb039237a25 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs
+++ b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs
@@ -9,3 +9,12 @@ Description:
automated testing or in situations, where other trigger methods
are not applicable. For example no RTC or spare GPIOs.
X is the IIO index of the trigger.
+
+What: /sys/bus/iio/devices/triggerX/name
+KernelVersion: 2.6.39
+Contact: linux-iio@vger.kernel.org
+Description:
+ The name attribute holds a description string for the current
+ trigger. In order to associate the trigger with an IIO device
+ one should write this name string to
+ /sys/bus/iio/devices/iio:deviceY/trigger/current_trigger.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index b6a6a2e0dd3b..9e086067b4ae 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -15,7 +15,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
80211.xml debugobjects.xml sh.xml regulator.xml \
alsa-driver-api.xml writing-an-alsa-driver.xml \
tracepoint.xml drm.xml media_api.xml w1.xml \
- writing_musb_glue_layer.xml crypto-API.xml
+ writing_musb_glue_layer.xml crypto-API.xml iio.xml
include Documentation/DocBook/media/Makefile
diff --git a/Documentation/DocBook/iio.tmpl b/Documentation/DocBook/iio.tmpl
new file mode 100644
index 000000000000..06bb53de5a47
--- /dev/null
+++ b/Documentation/DocBook/iio.tmpl
@@ -0,0 +1,697 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="iioid">
+ <bookinfo>
+ <title>Industrial I/O driver developer's guide </title>
+
+ <authorgroup>
+ <author>
+ <firstname>Daniel</firstname>
+ <surname>Baluta</surname>
+ <affiliation>
+ <address>
+ <email>daniel.baluta@intel.com</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2015</year>
+ <holder>Intel Corporation</holder>
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute
+ it and/or modify it under the terms of the GNU General Public
+ License version 2.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+ <toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ The main purpose of the Industrial I/O subsystem (IIO) is to provide
+ support for devices that in some sense perform either analog-to-digital
+ conversion (ADC) or digital-to-analog conversion (DAC) or both. The aim
+ is to fill the gap between the somewhat similar hwmon and input
+ subsystems.
+ Hwmon is directed at low sample rate sensors used to monitor and
+ control the system itself, like fan speed control or temperature
+ measurement. Input is, as its name suggests, focused on human interaction
+ input devices (keyboard, mouse, touchscreen). In some cases there is
+ considerable overlap between these and IIO.
+ </para>
+ <para>
+ Devices that fall into this category include:
+ <itemizedlist>
+ <listitem>
+ analog to digital converters (ADCs)
+ </listitem>
+ <listitem>
+ accelerometers
+ </listitem>
+ <listitem>
+ capacitance to digital converters (CDCs)
+ </listitem>
+ <listitem>
+ digital to analog converters (DACs)
+ </listitem>
+ <listitem>
+ gyroscopes
+ </listitem>
+ <listitem>
+ inertial measurement units (IMUs)
+ </listitem>
+ <listitem>
+ color and light sensors
+ </listitem>
+ <listitem>
+ magnetometers
+ </listitem>
+ <listitem>
+ pressure sensors
+ </listitem>
+ <listitem>
+ proximity sensors
+ </listitem>
+ <listitem>
+ temperature sensors
+ </listitem>
+ </itemizedlist>
+ Usually these sensors are connected via SPI or I2C. A common use case of the
+ sensors devices is to have combined functionality (e.g. light plus proximity
+ sensor).
+ </para>
+ </chapter>
+ <chapter id='iiosubsys'>
+ <title>Industrial I/O core</title>
+ <para>
+ The Industrial I/O core offers:
+ <itemizedlist>
+ <listitem>
+ a unified framework for writing drivers for many different types of
+ embedded sensors.
+ </listitem>
+ <listitem>
+ a standard interface to user space applications manipulating sensors.
+ </listitem>
+ </itemizedlist>
+ The implementation can be found under <filename>
+ drivers/iio/industrialio-*</filename>
+ </para>
+ <sect1 id="iiodevice">
+ <title> Industrial I/O devices </title>
+
+!Finclude/linux/iio/iio.h iio_dev
+!Fdrivers/iio/industrialio-core.c iio_device_alloc
+!Fdrivers/iio/industrialio-core.c iio_device_free
+!Fdrivers/iio/industrialio-core.c iio_device_register
+!Fdrivers/iio/industrialio-core.c iio_device_unregister
+
+ <para>
+ An IIO device usually corresponds to a single hardware sensor and it
+ provides all the information needed by a driver handling a device.
+ Let's first have a look at the functionality embedded in an IIO
+ device then we will show how a device driver makes use of an IIO
+ device.
+ </para>
+ <para>
+ There are two ways for a user space application to interact
+ with an IIO driver.
+ <itemizedlist>
+ <listitem>
+ <filename>/sys/bus/iio/iio:deviceX/</filename>, this
+ represents a hardware sensor and groups together the data
+ channels of the same chip.
+ </listitem>
+ <listitem>
+ <filename>/dev/iio:deviceX</filename>, character device node
+ interface used for buffered data transfer and for events information
+ retrieval.
+ </listitem>
+ </itemizedlist>
+ </para>
+ A typical IIO driver will register itself as an I2C or SPI driver and will
+ create two routines, <function> probe </function> and <function> remove
+ </function>. At <function>probe</function>:
+ <itemizedlist>
+ <listitem>call <function>iio_device_alloc</function>, which allocates memory
+ for an IIO device.
+ </listitem>
+ <listitem> initialize IIO device fields with driver specific information
+ (e.g. device name, device channels).
+ </listitem>
+ <listitem>call <function> iio_device_register</function>, this registers the
+ device with the IIO core. After this call the device is ready to accept
+ requests from user space applications.
+ </listitem>
+ </itemizedlist>
+ At <function>remove</function>, we free the resources allocated in
+ <function>probe</function> in reverse order:
+ <itemizedlist>
+ <listitem><function>iio_device_unregister</function>, unregister the device
+ from the IIO core.
+ </listitem>
+ <listitem><function>iio_device_free</function>, free the memory allocated
+ for the IIO device.
+ </listitem>
+ </itemizedlist>
+
+ <sect2 id="iioattr"> <title> IIO device sysfs interface </title>
+ <para>
+ Attributes are sysfs files used to expose chip info and also allowing
+ applications to set various configuration parameters. For device
+ with index X, attributes can be found under
+ <filename>/sys/bus/iio/iio:deviceX/ </filename> directory.
+ Common attributes are:
+ <itemizedlist>
+ <listitem><filename>name</filename>, description of the physical
+ chip.
+ </listitem>
+ <listitem><filename>dev</filename>, shows the major:minor pair
+ associated with <filename>/dev/iio:deviceX</filename> node.
+ </listitem>
+ <listitem><filename>sampling_frequency_available</filename>,
+ available discrete set of sampling frequency values for
+ device.
+ </listitem>
+ </itemizedlist>
+ Available standard attributes for IIO devices are described in the
+ <filename>Documentation/ABI/testing/sysfs-bus-iio </filename> file
+ in the Linux kernel sources.
+ </para>
+ </sect2>
+ <sect2 id="iiochannel"> <title> IIO device channels </title>
+!Finclude/linux/iio/iio.h iio_chan_spec structure.
+ <para>
+ An IIO device channel is a representation of a data channel. An
+ IIO device can have one or multiple channels. For example:
+ <itemizedlist>
+ <listitem>
+ a thermometer sensor has one channel representing the
+ temperature measurement.
+ </listitem>
+ <listitem>
+ a light sensor with two channels indicating the measurements in
+ the visible and infrared spectrum.
+ </listitem>
+ <listitem>
+ an accelerometer can have up to 3 channels representing
+ acceleration on X, Y and Z axes.
+ </listitem>
+ </itemizedlist>
+ An IIO channel is described by the <type> struct iio_chan_spec
+ </type>. A thermometer driver for the temperature sensor in the
+ example above would have to describe its channel as follows:
+ <programlisting>
+ static const struct iio_chan_spec temp_channel[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+ };
+
+ </programlisting>
+ Channel sysfs attributes exposed to userspace are specified in
+ the form of <emphasis>bitmasks</emphasis>. Depending on their
+ shared info, attributes can be set in one of the following masks:
+ <itemizedlist>
+ <listitem><emphasis>info_mask_separate</emphasis>, attributes will
+ be specific to this channel</listitem>
+ <listitem><emphasis>info_mask_shared_by_type</emphasis>,
+ attributes are shared by all channels of the same type</listitem>
+ <listitem><emphasis>info_mask_shared_by_dir</emphasis>, attributes
+ are shared by all channels of the same direction </listitem>
+ <listitem><emphasis>info_mask_shared_by_all</emphasis>,
+ attributes are shared by all channels</listitem>
+ </itemizedlist>
+ When there are multiple data channels per channel type we have two
+ ways to distinguish between them:
+ <itemizedlist>
+ <listitem> set <emphasis> .modified</emphasis> field of <type>
+ iio_chan_spec</type> to 1. Modifiers are specified using
+ <emphasis>.channel2</emphasis> field of the same
+ <type>iio_chan_spec</type> structure and are used to indicate a
+ physically unique characteristic of the channel such as its direction
+ or spectral response. For example, a light sensor can have two channels,
+ one for infrared light and one for both infrared and visible light.
+ </listitem>
+ <listitem> set <emphasis>.indexed </emphasis> field of
+ <type>iio_chan_spec</type> to 1. In this case the channel is
+ simply another instance with an index specified by the
+ <emphasis>.channel</emphasis> field.
+ </listitem>
+ </itemizedlist>
+ Here is how we can make use of the channel's modifiers:
+ <programlisting>
+ static const struct iio_chan_spec light_channels[] = {
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_IR,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_INTENSITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_BOTH,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+
+ }
+ </programlisting>
+ This channel's definition will generate two separate sysfs files
+ for raw data retrieval:
+ <itemizedlist>
+ <listitem>
+ <filename>/sys/bus/iio/iio:deviceX/in_intensity_ir_raw</filename>
+ </listitem>
+ <listitem>
+ <filename>/sys/bus/iio/iio:deviceX/in_intensity_both_raw</filename>
+ </listitem>
+ </itemizedlist>
+ one file for processed data:
+ <itemizedlist>
+ <listitem>
+ <filename>/sys/bus/iio/iio:deviceX/in_illuminance_input
+ </filename>
+ </listitem>
+ </itemizedlist>
+ and one shared sysfs file for sampling frequency:
+ <itemizedlist>
+ <listitem>
+ <filename>/sys/bus/iio/iio:deviceX/sampling_frequency.
+ </filename>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Here is how we can make use of the channel's indexing:
+ <programlisting>
+ static const struct iio_chan_spec light_channels[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ },
+ }
+ </programlisting>
+ This will generate two separate attributes files for raw data
+ retrieval:
+ <itemizedlist>
+ <listitem>
+ <filename>/sys/bus/iio/devices/iio:deviceX/in_voltage0_raw</filename>,
+ representing voltage measurement for channel 0.
+ </listitem>
+ <listitem>
+ <filename>/sys/bus/iio/devices/iio:deviceX/in_voltage1_raw</filename>,
+ representing voltage measurement for channel 1.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="iiobuffer"> <title> Industrial I/O buffers </title>
+!Finclude/linux/iio/buffer.h iio_buffer
+!Edrivers/iio/industrialio-buffer.c
+
+ <para>
+ The Industrial I/O core offers a way for continuous data capture
+ based on a trigger source. Multiple data channels can be read at once
+ from <filename>/dev/iio:deviceX</filename> character device node,
+ thus reducing the CPU load.
+ </para>
+
+ <sect2 id="iiobuffersysfs">
+ <title>IIO buffer sysfs interface </title>
+ <para>
+ An IIO buffer has an associated attributes directory under <filename>
+ /sys/bus/iio/iio:deviceX/buffer/</filename>. Here are the existing
+ attributes:
+ <itemizedlist>
+ <listitem>
+ <emphasis>length</emphasis>, the total number of data samples
+ (capacity) that can be stored by the buffer.
+ </listitem>
+ <listitem>
+ <emphasis>enable</emphasis>, activate buffer capture.
+ </listitem>
+ </itemizedlist>
+
+ </para>
+ </sect2>
+ <sect2 id="iiobuffersetup"> <title> IIO buffer setup </title>
+ <para>The meta information associated with a channel reading
+ placed in a buffer is called a <emphasis> scan element </emphasis>.
+ The important bits configuring scan elements are exposed to
+ userspace applications via the <filename>
+ /sys/bus/iio/iio:deviceX/scan_elements/</filename> directory. This
+ file contains attributes of the following form:
+ <itemizedlist>
+ <listitem><emphasis>enable</emphasis>, used for enabling a channel.
+ If and only if its attribute is non zero, then a triggered capture
+ will contain data samples for this channel.
+ </listitem>
+ <listitem><emphasis>type</emphasis>, description of the scan element
+ data storage within the buffer and hence the form in which it is
+ read from user space. Format is <emphasis>
+ [be|le]:[s|u]bits/storagebitsXrepeat[>>shift] </emphasis>.
+ <itemizedlist>
+ <listitem> <emphasis>be</emphasis> or <emphasis>le</emphasis>, specifies
+ big or little endian.
+ </listitem>
+ <listitem>
+ <emphasis>s </emphasis>or <emphasis>u</emphasis>, specifies if
+ signed (2's complement) or unsigned.
+ </listitem>
+ <listitem><emphasis>bits</emphasis>, is the number of valid data
+ bits.
+ </listitem>
+ <listitem><emphasis>storagebits</emphasis>, is the number of bits
+ (after padding) that it occupies in the buffer.
+ </listitem>
+ <listitem>
+ <emphasis>shift</emphasis>, if specified, is the shift that needs
+ to be applied prior to masking out unused bits.
+ </listitem>
+ <listitem>
+ <emphasis>repeat</emphasis>, specifies the number of bits/storagebits
+ repetitions. When the repeat element is 0 or 1, then the repeat
+ value is omitted.
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ For example, a driver for a 3-axis accelerometer with 12 bit
+ resolution where data is stored in two 8-bits registers as
+ follows:
+ <programlisting>
+ 7 6 5 4 3 2 1 0
+ +---+---+---+---+---+---+---+---+
+ |D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06)
+ +---+---+---+---+---+---+---+---+
+
+ 7 6 5 4 3 2 1 0
+ +---+---+---+---+---+---+---+---+
+ |D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07)
+ +---+---+---+---+---+---+---+---+
+ </programlisting>
+
+ will have the following scan element type for each axis:
+ <programlisting>
+ $ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type
+ le:s12/16>>4
+ </programlisting>
+ A user space application will interpret data samples read from the
+ buffer as two byte little endian signed data, that needs a 4 bits
+ right shift before masking out the 12 valid bits of data.
+ </para>
+ <para>
+ For implementing buffer support a driver should initialize the following
+ fields in <type>iio_chan_spec</type> definition:
+ <programlisting>
+ struct iio_chan_spec {
+ /* other members */
+ int scan_index
+ struct {
+ char sign;
+ u8 realbits;
+ u8 storagebits;
+ u8 shift;
+ u8 repeat;
+ enum iio_endian endianness;
+ } scan_type;
+ };
+ </programlisting>
+ The driver implementing the accelerometer described above will
+ have the following channel definition:
+ <programlisting>
+ struct struct iio_chan_spec accel_channels[] = {
+ {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ /* other stuff here */
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 12,
+ .storgebits = 16,
+ .shift = 4,
+ .endianness = IIO_LE,
+ },
+ }
+ /* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1)
+ * and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis
+ */
+ }
+ </programlisting>
+ </para>
+ <para>
+ Here <emphasis> scan_index </emphasis> defines the order in which
+ the enabled channels are placed inside the buffer. Channels with a lower
+ scan_index will be placed before channels with a higher index. Each
+ channel needs to have a unique scan_index.
+ </para>
+ <para>
+ Setting scan_index to -1 can be used to indicate that the specific
+ channel does not support buffered capture. In this case no entries will
+ be created for the channel in the scan_elements directory.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="iiotrigger"> <title> Industrial I/O triggers </title>
+!Finclude/linux/iio/trigger.h iio_trigger
+!Edrivers/iio/industrialio-trigger.c
+ <para>
+ In many situations it is useful for a driver to be able to
+ capture data based on some external event (trigger) as opposed
+ to periodically polling for data. An IIO trigger can be provided
+ by a device driver that also has an IIO device based on hardware
+ generated events (e.g. data ready or threshold exceeded) or
+ provided by a separate driver from an independent interrupt
+ source (e.g. GPIO line connected to some external system, timer
+ interrupt or user space writing a specific file in sysfs). A
+ trigger may initiate data capture for a number of sensors and
+ also it may be completely unrelated to the sensor itself.
+ </para>
+
+ <sect2 id="iiotrigsysfs"> <title> IIO trigger sysfs interface </title>
+ There are two locations in sysfs related to triggers:
+ <itemizedlist>
+ <listitem><filename>/sys/bus/iio/devices/triggerY</filename>,
+ this file is created once an IIO trigger is registered with
+ the IIO core and corresponds to trigger with index Y. Because
+ triggers can be very different depending on type there are few
+ standard attributes that we can describe here:
+ <itemizedlist>
+ <listitem>
+ <emphasis>name</emphasis>, trigger name that can be later
+ used for association with a device.
+ </listitem>
+ <listitem>
+ <emphasis>sampling_frequency</emphasis>, some timer based
+ triggers use this attribute to specify the frequency for
+ trigger calls.
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <filename>/sys/bus/iio/devices/iio:deviceX/trigger/</filename>, this
+ directory is created once the device supports a triggered
+ buffer. We can associate a trigger with our device by writing
+ the trigger's name in the <filename>current_trigger</filename> file.
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+ <sect2 id="iiotrigattr"> <title> IIO trigger setup</title>
+
+ <para>
+ Let's see a simple example of how to setup a trigger to be used
+ by a driver.
+
+ <programlisting>
+ struct iio_trigger_ops trigger_ops = {
+ .set_trigger_state = sample_trigger_state,
+ .validate_device = sample_validate_device,
+ }
+
+ struct iio_trigger *trig;
+
+ /* first, allocate memory for our trigger */
+ trig = iio_trigger_alloc(dev, "trig-%s-%d", name, idx);
+
+ /* setup trigger operations field */
+ trig->ops = &amp;trigger_ops;
+
+ /* now register the trigger with the IIO core */
+ iio_trigger_register(trig);
+ </programlisting>
+ </para>
+ </sect2>
+
+ <sect2 id="iiotrigsetup"> <title> IIO trigger ops</title>
+!Finclude/linux/iio/trigger.h iio_trigger_ops
+ <para>
+ Notice that a trigger has a set of operations attached:
+ <itemizedlist>
+ <listitem>
+ <function>set_trigger_state</function>, switch the trigger on/off
+ on demand.
+ </listitem>
+ <listitem>
+ <function>validate_device</function>, function to validate the
+ device when the current trigger gets changed.
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+ </sect1>
+ <sect1 id="iiotriggered_buffer">
+ <title> Industrial I/O triggered buffers </title>
+ <para>
+ Now that we know what buffers and triggers are let's see how they
+ work together.
+ </para>
+ <sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title>
+!Edrivers/iio/industrialio-triggered-buffer.c
+!Finclude/linux/iio/iio.h iio_buffer_setup_ops
+
+
+ <para>
+ A typical triggered buffer setup looks like this:
+ <programlisting>
+ const struct iio_buffer_setup_ops sensor_buffer_setup_ops = {
+ .preenable = sensor_buffer_preenable,
+ .postenable = sensor_buffer_postenable,
+ .postdisable = sensor_buffer_postdisable,
+ .predisable = sensor_buffer_predisable,
+ };
+
+ irqreturn_t sensor_iio_pollfunc(int irq, void *p)
+ {
+ pf->timestamp = iio_get_time_ns();
+ return IRQ_WAKE_THREAD;
+ }
+
+ irqreturn_t sensor_trigger_handler(int irq, void *p)
+ {
+ u16 buf[8];
+ int i = 0;
+
+ /* read data for each active channel */
+ for_each_set_bit(bit, active_scan_mask, masklength)
+ buf[i++] = sensor_get_data(bit)
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp);
+
+ iio_trigger_notify_done(trigger);
+ return IRQ_HANDLED;
+ }
+
+ /* setup triggered buffer, usually in probe function */
+ iio_triggered_buffer_setup(indio_dev, sensor_iio_polfunc,
+ sensor_trigger_handler,
+ sensor_buffer_setup_ops);
+ </programlisting>
+ </para>
+ The important things to notice here are:
+ <itemizedlist>
+ <listitem><function> iio_buffer_setup_ops</function>, the buffer setup
+ functions to be called at predefined points in the buffer configuration
+ sequence (e.g. before enable, after disable). If not specified, the
+ IIO core uses the default <type>iio_triggered_buffer_setup_ops</type>.
+ </listitem>
+ <listitem><function>sensor_iio_pollfunc</function>, the function that
+ will be used as top half of poll function. It should do as little
+ processing as possible, because it runs in interrupt context. The most
+ common operation is recording of the current timestamp and for this reason
+ one can use the IIO core defined <function>iio_pollfunc_store_time
+ </function> function.
+ </listitem>
+ <listitem><function>sensor_trigger_handler</function>, the function that
+ will be used as bottom half of the poll function. This runs in the
+ context of a kernel thread and all the processing takes place here.
+ It usually reads data from the device and stores it in the internal
+ buffer together with the timestamp recorded in the top half.
+ </listitem>
+ </itemizedlist>
+ </sect2>
+ </sect1>
+ </chapter>
+ <chapter id='iioresources'>
+ <title> Resources </title>
+ IIO core may change during time so the best documentation to read is the
+ source code. There are several locations where you should look:
+ <itemizedlist>
+ <listitem>
+ <filename>drivers/iio/</filename>, contains the IIO core plus
+ and directories for each sensor type (e.g. accel, magnetometer,
+ etc.)
+ </listitem>
+ <listitem>
+ <filename>include/linux/iio/</filename>, contains the header
+ files, nice to read for the internal kernel interfaces.
+ </listitem>
+ <listitem>
+ <filename>include/uapi/linux/iio/</filename>, contains files to be
+ used by user space applications.
+ </listitem>
+ <listitem>
+ <filename>tools/iio/</filename>, contains tools for rapidly
+ testing buffers, events and device creation.
+ </listitem>
+ <listitem>
+ <filename>drivers/staging/iio/</filename>, contains code for some
+ drivers or experimental features that are not yet mature enough
+ to be moved out.
+ </listitem>
+ </itemizedlist>
+ <para>
+ Besides the code, there are some good online documentation sources:
+ <itemizedlist>
+ <listitem>
+ <ulink url="http://marc.info/?l=linux-iio"> Industrial I/O mailing
+ list </ulink>
+ </listitem>
+ <listitem>
+ <ulink url="http://wiki.analog.com/software/linux/docs/iio/iio">
+ Analog Device IIO wiki page </ulink>
+ </listitem>
+ <listitem>
+ <ulink url="https://fosdem.org/2015/schedule/event/iiosdr/">
+ Using the Linux IIO framework for SDR, Lars-Peter Clausen's
+ presentation at FOSDEM </ulink>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </chapter>
+</book>
+
+<!--
+vim: softtabstop=2:shiftwidth=2:expandtab:textwidth=72
+-->
diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
index b85184391b78..2a1f3af30155 100644
--- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
+++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt
@@ -18,6 +18,7 @@ Required properties:
"mcp3202"
"mcp3204"
"mcp3208"
+ "mcp3301"
Examples:
diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
index 3eb40e20c143..1aad0514e647 100644
--- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt
@@ -17,6 +17,11 @@ Recommended properties:
- Frequency in normal mode (ADLPC=0, ADHSC=0)
- Frequency in high-speed mode (ADLPC=0, ADHSC=1)
- Frequency in low-power mode (ADLPC=1, ADHSC=0)
+- min-sample-time: Minimum sampling time in nanoseconds. This value has
+ to be chosen according to the conversion mode and the connected analog
+ source resistance (R_as) and capacitance (C_as). Refer the datasheet's
+ operating requirements. A safe default across a wide range of R_as and
+ C_as as well as conversion modes is 1000ns.
Example:
adc0: adc@4003b000 {
diff --git a/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt b/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt
new file mode 100644
index 000000000000..a01235c7fa15
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/magnetometer/mmc35240.txt
@@ -0,0 +1,13 @@
+* MEMSIC MMC35240 magnetometer sensor
+
+Required properties:
+
+ - compatible : should be "memsic,mmc35240"
+ - reg : the I2C address of the magnetometer
+
+Example:
+
+mmc35240@30 {
+ compatible = "memsic,mmc35240";
+ reg = <0x30>;
+};
diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt
index 8a6be3bdf267..d3ccdb190c53 100644
--- a/Documentation/devicetree/bindings/iio/st-sensors.txt
+++ b/Documentation/devicetree/bindings/iio/st-sensors.txt
@@ -35,6 +35,7 @@ Accelerometers:
- st,lsm303dl-accel
- st,lsm303dlm-accel
- st,lsm330-accel
+- st,lsm303agr-accel
Gyroscopes:
- st,l3g4200d-gyro
@@ -46,6 +47,7 @@ Gyroscopes:
- st,lsm330-gyro
Magnetometers:
+- st,lsm303agr-magn
- st,lsm303dlh-magn
- st,lsm303dlhc-magn
- st,lsm303dlm-magn
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
index 307537787574..555fb117d4fa 100644
--- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
+++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
@@ -1,4 +1,4 @@
-* Freescale i.MX28 LRADC device driver
+* Freescale MXS LRADC device driver
Required properties:
- compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc"
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 00e7bcbdbe24..a59047d7657e 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -86,18 +86,6 @@ config KXSD9
To compile this driver as a module, choose M here: the module
will be called kxsd9.
-config MMA8452
- tristate "Freescale MMA8452Q Accelerometer Driver"
- depends on I2C
- select IIO_BUFFER
- select IIO_TRIGGERED_BUFFER
- help
- Say yes here to build support for the Freescale MMA8452Q 3-axis
- accelerometer.
-
- To compile this driver as a module, choose M here: the module
- will be called mma8452.
-
config KXCJK1013
tristate "Kionix 3-Axis Accelerometer Driver"
depends on I2C
@@ -111,6 +99,18 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
+config MMA8452
+ tristate "Freescale MMA8452Q Accelerometer Driver"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for the Freescale MMA8452Q 3-axis
+ accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mma8452.
+
config MMA9551_CORE
tristate
@@ -140,6 +140,8 @@ config MMA9553
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
help
Say yes here to get support for the Sensortek STK8312 3-axis
accelerometer.
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index e84e2a1646df..0104cdef8709 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -151,6 +151,7 @@ struct bmc150_scale_info {
};
struct bmc150_accel_chip_info {
+ const char *name;
u8 chip_id;
const struct iio_chan_spec *channels;
int num_channels;
@@ -345,63 +346,6 @@ static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t,
return 0;
}
-static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
-{
- int ret;
-
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error: Reading chip id\n");
- return ret;
- }
-
- dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
- if (ret != data->chip_info->chip_id) {
- dev_err(&data->client->dev, "Invalid chip %x\n", ret);
- return -ENODEV;
- }
-
- ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
- if (ret < 0)
- return ret;
-
- /* Set Bandwidth */
- ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
- if (ret < 0)
- return ret;
-
- /* Set Default Range */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_PMU_RANGE,
- BMC150_ACCEL_DEF_RANGE_4G);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
- return ret;
- }
-
- data->range = BMC150_ACCEL_DEF_RANGE_4G;
-
- /* Set default slope duration and thresholds */
- data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
- data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
- ret = bmc150_accel_update_slope(data);
- if (ret < 0)
- return ret;
-
- /* Set default as latched interrupts */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
- if (ret < 0) {
- dev_err(&data->client->dev,
- "Error writing reg_int_rst_latch\n");
- return ret;
- }
-
- return 0;
-}
-
static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
int *val2)
{
@@ -1119,6 +1063,7 @@ enum {
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
[bmc150] = {
+ .name = "BMC150A",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@@ -1128,6 +1073,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bmi055] = {
+ .name = "BMI055A",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@@ -1137,6 +1083,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma255] = {
+ .name = "BMA0255",
.chip_id = 0xFA,
.channels = bmc150_accel_channels,
.num_channels = ARRAY_SIZE(bmc150_accel_channels),
@@ -1146,6 +1093,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{76590, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma250e] = {
+ .name = "BMA250E",
.chip_id = 0xF9,
.channels = bma250e_accel_channels,
.num_channels = ARRAY_SIZE(bma250e_accel_channels),
@@ -1155,6 +1103,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{306457, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma222e] = {
+ .name = "BMA222E",
.chip_id = 0xF8,
.channels = bma222e_accel_channels,
.num_channels = ARRAY_SIZE(bma222e_accel_channels),
@@ -1164,6 +1113,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
{1225831, BMC150_ACCEL_DEF_RANGE_16G} },
},
[bma280] = {
+ .name = "BMA0280",
.chip_id = 0xFB,
.channels = bma280_accel_channels,
.num_channels = ARRAY_SIZE(bma280_accel_channels),
@@ -1410,20 +1360,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
return IRQ_NONE;
}
-static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data)
-{
- const struct acpi_device_id *id;
-
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
-
- if (!id)
- return NULL;
-
- *data = (int)id->driver_data;
-
- return dev_name(dev);
-}
-
static int bmc150_accel_gpio_probe(struct i2c_client *client,
struct bmc150_accel_data *data)
{
@@ -1618,6 +1554,70 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
.postdisable = bmc150_accel_buffer_postdisable,
};
+static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
+{
+ int ret, i;
+
+ ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error: Reading chip id\n");
+ return ret;
+ }
+
+ dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
+ for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
+ if (bmc150_accel_chip_info_tbl[i].chip_id == ret) {
+ data->chip_info = &bmc150_accel_chip_info_tbl[i];
+ break;
+ }
+ }
+
+ if (!data->chip_info) {
+ dev_err(&data->client->dev, "Unsupported chip %x\n", ret);
+ return -ENODEV;
+ }
+
+ ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Set Bandwidth */
+ ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Set Default Range */
+ ret = i2c_smbus_write_byte_data(data->client,
+ BMC150_ACCEL_REG_PMU_RANGE,
+ BMC150_ACCEL_DEF_RANGE_4G);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
+ return ret;
+ }
+
+ data->range = BMC150_ACCEL_DEF_RANGE_4G;
+
+ /* Set default slope duration and thresholds */
+ data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD;
+ data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION;
+ ret = bmc150_accel_update_slope(data);
+ if (ret < 0)
+ return ret;
+
+ /* Set default as latched interrupts */
+ ret = i2c_smbus_write_byte_data(data->client,
+ BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Error writing reg_int_rst_latch\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int bmc150_accel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1625,7 +1625,6 @@ static int bmc150_accel_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret;
const char *name = NULL;
- int chip_id = 0;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@@ -1635,15 +1634,8 @@ static int bmc150_accel_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
data->client = client;
- if (id) {
+ if (id)
name = id->name;
- chip_id = id->driver_data;
- }
-
- if (ACPI_HANDLE(&client->dev))
- name = bmc150_accel_match_acpi_device(&client->dev, &chip_id);
-
- data->chip_info = &bmc150_accel_chip_info_tbl[chip_id];
ret = bmc150_accel_chip_init(data);
if (ret < 0)
@@ -1654,7 +1646,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
indio_dev->dev.parent = &client->dev;
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
- indio_dev->name = name;
+ indio_dev->name = name ? name : data->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_accel_info;
@@ -1670,7 +1662,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = bmc150_accel_gpio_probe(client, data);
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(
&client->dev, client->irq,
bmc150_accel_irq_handler,
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 8128579bff79..3292bc0c1d0e 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1240,7 +1240,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = kxcjk1013_gpio_probe(client, data);
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kxcjk1013_data_rdy_trig_poll,
kxcjk1013_event_handler,
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 13ea1ea23328..b921d84c1be6 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
@@ -24,54 +23,51 @@
#include <linux/iio/events.h>
#include <linux/delay.h>
-#define MMA8452_STATUS 0x00
-#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
-#define MMA8452_OUT_Y 0x03
-#define MMA8452_OUT_Z 0x05
-#define MMA8452_INT_SRC 0x0c
-#define MMA8452_WHO_AM_I 0x0d
-#define MMA8452_DATA_CFG 0x0e
-#define MMA8452_HP_FILTER_CUTOFF 0x0f
-#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1))
-#define MMA8452_TRANSIENT_CFG 0x1d
-#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
-#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
-#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
-#define MMA8452_TRANSIENT_SRC 0x1e
-#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
-#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
-#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
-#define MMA8452_TRANSIENT_THS 0x1f
-#define MMA8452_TRANSIENT_THS_MASK 0x7f
-#define MMA8452_TRANSIENT_COUNT 0x20
-#define MMA8452_OFF_X 0x2f
-#define MMA8452_OFF_Y 0x30
-#define MMA8452_OFF_Z 0x31
-#define MMA8452_CTRL_REG1 0x2a
-#define MMA8452_CTRL_REG2 0x2b
-#define MMA8452_CTRL_REG2_RST BIT(6)
-#define MMA8452_CTRL_REG4 0x2d
-#define MMA8452_CTRL_REG5 0x2e
-
-#define MMA8452_MAX_REG 0x31
-
-#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
-
-#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3))
-#define MMA8452_CTRL_DR_SHIFT 3
-#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
-#define MMA8452_CTRL_ACTIVE BIT(0)
-
-#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0))
-#define MMA8452_DATA_CFG_FS_2G 0
-#define MMA8452_DATA_CFG_FS_4G 1
-#define MMA8452_DATA_CFG_FS_8G 2
-#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
-
-#define MMA8452_INT_DRDY BIT(0)
-#define MMA8452_INT_TRANS BIT(5)
-
-#define MMA8452_DEVICE_ID 0x2a
+#define MMA8452_STATUS 0x00
+#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
+#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */
+#define MMA8452_OUT_Y 0x03
+#define MMA8452_OUT_Z 0x05
+#define MMA8452_INT_SRC 0x0c
+#define MMA8452_WHO_AM_I 0x0d
+#define MMA8452_DATA_CFG 0x0e
+#define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0)
+#define MMA8452_DATA_CFG_FS_2G 0
+#define MMA8452_DATA_CFG_FS_4G 1
+#define MMA8452_DATA_CFG_FS_8G 2
+#define MMA8452_DATA_CFG_HPF_MASK BIT(4)
+#define MMA8452_HP_FILTER_CUTOFF 0x0f
+#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0)
+#define MMA8452_TRANSIENT_CFG 0x1d
+#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
+#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
+#define MMA8452_TRANSIENT_CFG_ELE BIT(4)
+#define MMA8452_TRANSIENT_SRC 0x1e
+#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
+#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
+#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
+#define MMA8452_TRANSIENT_THS 0x1f
+#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0)
+#define MMA8452_TRANSIENT_COUNT 0x20
+#define MMA8452_CTRL_REG1 0x2a
+#define MMA8452_CTRL_ACTIVE BIT(0)
+#define MMA8452_CTRL_DR_MASK GENMASK(5, 3)
+#define MMA8452_CTRL_DR_SHIFT 3
+#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
+#define MMA8452_CTRL_REG2 0x2b
+#define MMA8452_CTRL_REG2_RST BIT(6)
+#define MMA8452_CTRL_REG4 0x2d
+#define MMA8452_CTRL_REG5 0x2e
+#define MMA8452_OFF_X 0x2f
+#define MMA8452_OFF_Y 0x30
+#define MMA8452_OFF_Z 0x31
+
+#define MMA8452_MAX_REG 0x31
+
+#define MMA8452_INT_DRDY BIT(0)
+#define MMA8452_INT_TRANS BIT(5)
+
+#define MMA8452_DEVICE_ID 0x2a
struct mma8452_data {
struct i2c_client *client;
@@ -91,30 +87,34 @@ static int mma8452_drdy(struct mma8452_data *data)
return ret;
if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY)
return 0;
+
msleep(20);
}
dev_err(&data->client->dev, "data not ready\n");
+
return -EIO;
}
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
{
int ret = mma8452_drdy(data);
+
if (ret < 0)
return ret;
- return i2c_smbus_read_i2c_block_data(data->client,
- MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf);
+
+ return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
+ 3 * sizeof(__be16), (u8 *)buf);
}
-static ssize_t mma8452_show_int_plus_micros(char *buf,
- const int (*vals)[2], int n)
+static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
+ int n)
{
size_t len = 0;
while (n-- > 0)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "%d.%06d ", vals[n][0], vals[n][1]);
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
+ vals[n][0], vals[n][1]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
@@ -123,7 +123,7 @@ static ssize_t mma8452_show_int_plus_micros(char *buf,
}
static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n,
- int val, int val2)
+ int val, int val2)
{
while (n-- > 0)
if (val == vals[n][0] && val2 == vals[n][1])
@@ -147,7 +147,7 @@ static const int mma8452_samp_freq[8][2] = {
* Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
* The userspace interface uses m/s^2 and we declare micro units
* So scale factor is given by:
- * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
+ * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665
*/
static const int mma8452_scales[3][2] = {
{0, 9577}, {0, 19154}, {0, 38307}
@@ -178,17 +178,19 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = {
};
static ssize_t mma8452_show_samp_freq_avail(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
return mma8452_show_int_plus_micros(buf, mma8452_samp_freq,
- ARRAY_SIZE(mma8452_samp_freq));
+ ARRAY_SIZE(mma8452_samp_freq));
}
static ssize_t mma8452_show_scale_avail(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
return mma8452_show_int_plus_micros(buf, mma8452_scales,
- ARRAY_SIZE(mma8452_scales));
+ ARRAY_SIZE(mma8452_scales));
}
static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
@@ -205,22 +207,23 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev,
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail);
static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO,
- mma8452_show_scale_avail, NULL, 0);
+ mma8452_show_scale_avail, NULL, 0);
static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available,
- S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
+ S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0);
static int mma8452_get_samp_freq_index(struct mma8452_data *data,
- int val, int val2)
+ int val, int val2)
{
return mma8452_get_int_plus_micros_index(mma8452_samp_freq,
- ARRAY_SIZE(mma8452_samp_freq), val, val2);
+ ARRAY_SIZE(mma8452_samp_freq),
+ val, val2);
}
-static int mma8452_get_scale_index(struct mma8452_data *data,
- int val, int val2)
+static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2)
{
return mma8452_get_int_plus_micros_index(mma8452_scales,
- ARRAY_SIZE(mma8452_scales), val, val2);
+ ARRAY_SIZE(mma8452_scales),
+ val, val2);
}
static int mma8452_get_hp_filter_index(struct mma8452_data *data,
@@ -229,7 +232,7 @@ static int mma8452_get_hp_filter_index(struct mma8452_data *data,
int i = mma8452_get_odr_index(data);
return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i],
- ARRAY_SIZE(mma8452_scales[0]), val, val2);
+ ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2);
}
static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
@@ -266,25 +269,31 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
- *val = sign_extend32(
- be16_to_cpu(buffer[chan->scan_index]) >> 4, 11);
+
+ *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4,
+ 11);
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK;
*val = mma8452_scales[i][0];
*val2 = mma8452_scales[i][1];
+
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
i = mma8452_get_odr_index(data);
*val = mma8452_samp_freq[i][0];
*val2 = mma8452_samp_freq[i][1];
+
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_CALIBBIAS:
- ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X +
- chan->scan_index);
+ ret = i2c_smbus_read_byte_data(data->client,
+ MMA8452_OFF_X + chan->scan_index);
if (ret < 0)
return ret;
+
*val = sign_extend32(ret, 7);
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) {
@@ -295,21 +304,23 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
*val = 0;
*val2 = 0;
}
+
return IIO_VAL_INT_PLUS_MICRO;
}
+
return -EINVAL;
}
static int mma8452_standby(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
- data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
+ data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE);
}
static int mma8452_active(struct mma8452_data *data)
{
return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1,
- data->ctrl_reg1);
+ data->ctrl_reg1);
}
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
@@ -334,6 +345,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
ret = 0;
fail:
mutex_unlock(&data->lock);
+
return ret;
}
@@ -344,12 +356,13 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data,
i = mma8452_get_hp_filter_index(data, val, val2);
if (i < 0)
- return -EINVAL;
+ return i;
reg = i2c_smbus_read_byte_data(data->client,
MMA8452_HP_FILTER_CUTOFF);
if (reg < 0)
return reg;
+
reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
reg |= i;
@@ -370,25 +383,30 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
i = mma8452_get_samp_freq_index(data, val, val2);
if (i < 0)
- return -EINVAL;
+ return i;
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
+
return mma8452_change_config(data, MMA8452_CTRL_REG1,
- data->ctrl_reg1);
+ data->ctrl_reg1);
case IIO_CHAN_INFO_SCALE:
i = mma8452_get_scale_index(data, val, val2);
if (i < 0)
- return -EINVAL;
+ return i;
+
data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK;
data->data_cfg |= i;
+
return mma8452_change_config(data, MMA8452_DATA_CFG,
- data->data_cfg);
+ data->data_cfg);
case IIO_CHAN_INFO_CALIBBIAS:
if (val < -128 || val > 127)
return -EINVAL;
- return mma8452_change_config(data, MMA8452_OFF_X +
- chan->scan_index, val);
+
+ return mma8452_change_config(data,
+ MMA8452_OFF_X + chan->scan_index,
+ val);
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
if (val == 0 && val2 == 0) {
@@ -399,8 +417,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
}
+
return mma8452_change_config(data, MMA8452_DATA_CFG,
- data->data_cfg);
+ data->data_cfg);
default:
return -EINVAL;
@@ -425,6 +444,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
return ret;
*val = ret & MMA8452_TRANSIENT_THS_MASK;
+
return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
@@ -437,6 +457,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
mma8452_get_odr_index(data)];
*val = us / USEC_PER_SEC;
*val2 = us % USEC_PER_SEC;
+
return IIO_VAL_INT_PLUS_MICRO;
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
@@ -453,6 +474,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
}
+
return IIO_VAL_INT_PLUS_MICRO;
default:
@@ -472,19 +494,22 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
switch (info) {
case IIO_EV_INFO_VALUE:
- return mma8452_change_config(data, MMA8452_TRANSIENT_THS,
- val & MMA8452_TRANSIENT_THS_MASK);
+ if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK)
+ return -EINVAL;
+
+ return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val);
case IIO_EV_INFO_PERIOD:
steps = (val * USEC_PER_SEC + val2) /
mma8452_transient_time_step_us[
mma8452_get_odr_index(data)];
- if (steps > 0xff)
+ if (steps < 0 || steps > 0xff)
return -EINVAL;
return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT,
steps);
+
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB:
reg = i2c_smbus_read_byte_data(data->client,
MMA8452_TRANSIENT_CFG);
@@ -499,6 +524,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
}
+
return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg);
default:
@@ -608,15 +634,16 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p)
u8 buffer[16]; /* 3 16-bit channels + padding + ts */
int ret;
- ret = mma8452_read(data, (__be16 *) buffer);
+ ret = mma8452_read(data, (__be16 *)buffer);
if (ret < 0)
goto done;
iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- iio_get_time_ns());
+ iio_get_time_ns());
done:
iio_trigger_notify_done(indio_dev->trig);
+
return IRQ_HANDLED;
}
@@ -674,10 +701,10 @@ static struct attribute_group mma8452_event_attribute_group = {
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
- BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = idx, \
.scan_type = { \
.sign = 's', \
@@ -780,6 +807,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev)
return ret;
indio_dev->trig = trig;
+
return 0;
}
@@ -849,7 +877,7 @@ static int mma8452_probe(struct i2c_client *client,
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
- data->data_cfg);
+ data->data_cfg);
if (ret < 0)
return ret;
@@ -891,14 +919,14 @@ static int mma8452_probe(struct i2c_client *client,
}
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
- (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
+ (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
if (ret < 0)
goto trigger_cleanup;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
- mma8452_trigger_handler, NULL);
+ mma8452_trigger_handler, NULL);
if (ret < 0)
goto trigger_cleanup;
@@ -968,6 +996,7 @@ static const struct of_device_id mma8452_dt_ids[] = {
{ .compatible = "fsl,mma8452" },
{ }
};
+MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
static struct i2c_driver mma8452_driver = {
.driver = {
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index a605280637e9..771858cb67a1 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -1149,7 +1149,7 @@ static int mma9553_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = mma9553_gpio_probe(client);
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
mma9553_irq_handler,
mma9553_event_handler,
diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h
index aa1001931d0c..468f21fa2950 100644
--- a/drivers/iio/accel/st_accel.h
+++ b/drivers/iio/accel/st_accel.h
@@ -26,6 +26,7 @@
#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
#define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel"
#define LSM330_ACCEL_DEV_NAME "lsm330_accel"
+#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel"
/**
* struct st_sensors_platform_data - default accel platform data
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index 4002e6410444..ff30f8806880 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -226,12 +226,14 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = {
static const struct st_sensor_settings st_accel_sensors_settings[] = {
{
.wai = ST_ACCEL_1_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3DH_ACCEL_DEV_NAME,
[1] = LSM303DLHC_ACCEL_DEV_NAME,
[2] = LSM330D_ACCEL_DEV_NAME,
[3] = LSM330DL_ACCEL_DEV_NAME,
[4] = LSM330DLC_ACCEL_DEV_NAME,
+ [5] = LSM303AGR_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
@@ -297,6 +299,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_2_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS331DLH_ACCEL_DEV_NAME,
[1] = LSM303DL_ACCEL_DEV_NAME,
@@ -359,6 +362,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_3_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM330_ACCEL_DEV_NAME,
},
@@ -437,6 +441,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_4_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3LV02DL_ACCEL_DEV_NAME,
},
@@ -494,6 +499,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
{
.wai = ST_ACCEL_5_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS331DL_ACCEL_DEV_NAME,
},
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index a2f1c20319eb..8b9cc84fd44f 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lsm330-accel",
.data = LSM330_ACCEL_DEV_NAME,
},
+ {
+ .compatible = "st,lsm303agr-accel",
+ .data = LSM303AGR_ACCEL_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
+ { LSM303AGR_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index 12ec29389e4b..54b61a3961c3 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = {
{ LSM303DL_ACCEL_DEV_NAME },
{ LSM303DLM_ACCEL_DEV_NAME },
{ LSM330_ACCEL_DEV_NAME },
+ { LSM303AGR_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index c2bd1444d6da..c764af284c94 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -37,16 +37,16 @@
#define STK8312_REG_OTPDATA 0x3E
#define STK8312_REG_OTPCTRL 0x3F
-#define STK8312_MODE_ACTIVE 0x01
+#define STK8312_MODE_ACTIVE BIT(0)
#define STK8312_MODE_STANDBY 0x00
-#define STK8312_DREADY_BIT 0x10
-#define STK8312_INT_MODE 0xC0
-#define STK8312_RNG_MASK 0xC0
-#define STK8312_SR_MASK 0x07
-#define STK8312_SR_400HZ_IDX 0
+#define STK8312_MODE_INT_AH_PP 0xC0 /* active-high, push-pull */
+#define STK8312_DREADY_BIT BIT(4)
+#define STK8312_RNG_6G 1
#define STK8312_RNG_SHIFT 6
-#define STK8312_READ_RETRIES 16
-#define STK8312_ALL_CHANNEL_MASK 7
+#define STK8312_RNG_MASK GENMASK(7, 6)
+#define STK8312_SR_MASK GENMASK(2, 0)
+#define STK8312_SR_400HZ_IDX 0
+#define STK8312_ALL_CHANNEL_MASK GENMASK(2, 0)
#define STK8312_ALL_CHANNEL_SIZE 3
#define STK8312_DRIVER_NAME "stk8312"
@@ -69,8 +69,8 @@ static const int stk8312_scale_table[][2] = {
};
static const struct {
- u16 val;
- u32 val2;
+ int val;
+ int val2;
} stk8312_samp_freq_table[] = {
{400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0},
{12, 500000}, {6, 250000}, {3, 125000}
@@ -103,7 +103,7 @@ static const struct iio_chan_spec stk8312_channels[] = {
struct stk8312_data {
struct i2c_client *client;
struct mutex lock;
- int range;
+ u8 range;
u8 sample_rate_idx;
u8 mode;
struct iio_trigger *dready_trig;
@@ -144,22 +144,25 @@ static int stk8312_otp_init(struct stk8312_data *data)
if (ret < 0)
goto exit_err;
count--;
- } while (!(ret & 0x80) && count > 0);
+ } while (!(ret & BIT(7)) && count > 0);
- if (count == 0)
+ if (count == 0) {
+ ret = -ETIMEDOUT;
goto exit_err;
+ }
ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA);
+ if (ret == 0)
+ ret = -EINVAL;
if (ret < 0)
goto exit_err;
- ret = i2c_smbus_write_byte_data(data->client,
- STK8312_REG_AFECTRL, ret);
+ ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_AFECTRL, ret);
if (ret < 0)
goto exit_err;
msleep(150);
- return ret;
+ return 0;
exit_err:
dev_err(&client->dev, "failed to initialize sensor\n");
@@ -203,8 +206,11 @@ static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask)
return ret;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask);
- if (ret < 0)
+ if (ret < 0) {
dev_err(&client->dev, "failed to set interrupts\n");
+ stk8312_set_mode(data, mode);
+ return ret;
+ }
return stk8312_set_mode(data, mode);
}
@@ -228,7 +234,7 @@ static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig,
data->dready_trigger_on = state;
- return ret;
+ return 0;
}
static const struct iio_trigger_ops stk8312_trigger_ops = {
@@ -236,7 +242,7 @@ static const struct iio_trigger_ops stk8312_trigger_ops = {
.owner = THIS_MODULE,
};
-static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
+static int stk8312_set_sample_rate(struct stk8312_data *data, u8 rate)
{
int ret;
u8 masked_reg;
@@ -253,20 +259,24 @@ static int stk8312_set_sample_rate(struct stk8312_data *data, int rate)
return ret;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR);
- if (ret < 0) {
- dev_err(&client->dev, "failed to set sampling rate\n");
- return ret;
- }
+ if (ret < 0)
+ goto err_activate;
masked_reg = (ret & (~STK8312_SR_MASK)) | rate;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg);
if (ret < 0)
- dev_err(&client->dev, "failed to set sampling rate\n");
- else
- data->sample_rate_idx = rate;
+ goto err_activate;
+
+ data->sample_rate_idx = rate;
return stk8312_set_mode(data, mode);
+
+err_activate:
+ dev_err(&client->dev, "failed to set sampling rate\n");
+ stk8312_set_mode(data, mode);
+
+ return ret;
}
static int stk8312_set_range(struct stk8312_data *data, u8 range)
@@ -288,21 +298,25 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range)
return ret;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH);
- if (ret < 0) {
- dev_err(&client->dev, "failed to change sensor range\n");
- return ret;
- }
+ if (ret < 0)
+ goto err_activate;
masked_reg = ret & (~STK8312_RNG_MASK);
masked_reg |= range << STK8312_RNG_SHIFT;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg);
if (ret < 0)
- dev_err(&client->dev, "failed to change sensor range\n");
- else
- data->range = range;
+ goto err_activate;
+
+ data->range = range;
return stk8312_set_mode(data, mode);
+
+err_activate:
+ dev_err(&client->dev, "failed to change sensor range\n");
+ stk8312_set_mode(data, mode);
+
+ return ret;
}
static int stk8312_read_accel(struct stk8312_data *data, u8 address)
@@ -335,18 +349,21 @@ static int stk8312_read_raw(struct iio_dev *indio_dev,
ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE);
if (ret < 0) {
mutex_unlock(&data->lock);
- return -EINVAL;
+ return ret;
}
ret = stk8312_read_accel(data, chan->address);
if (ret < 0) {
stk8312_set_mode(data,
data->mode & (~STK8312_MODE_ACTIVE));
mutex_unlock(&data->lock);
- return -EINVAL;
+ return ret;
}
*val = sign_extend32(ret, 7);
- stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE));
+ ret = stk8312_set_mode(data,
+ data->mode & (~STK8312_MODE_ACTIVE));
mutex_unlock(&data->lock);
+ if (ret < 0)
+ return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = stk8312_scale_table[data->range - 1][0];
@@ -418,7 +435,6 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct stk8312_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
- u8 buffer[STK8312_ALL_CHANNEL_SIZE];
mutex_lock(&data->lock);
/*
@@ -429,18 +445,15 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p)
ret = i2c_smbus_read_i2c_block_data(data->client,
STK8312_REG_XOUT,
STK8312_ALL_CHANNEL_SIZE,
- buffer);
+ data->buffer);
if (ret < STK8312_ALL_CHANNEL_SIZE) {
dev_err(&data->client->dev, "register read failed\n");
mutex_unlock(&data->lock);
goto err;
}
- data->buffer[0] = buffer[0];
- data->buffer[1] = buffer[1];
- data->buffer[2] = buffer[2];
} else {
for_each_set_bit(bit, indio_dev->active_scan_mask,
- indio_dev->masklength) {
+ indio_dev->masklength) {
ret = stk8312_read_accel(data, bit);
if (ret < 0) {
mutex_unlock(&data->lock);
@@ -547,11 +560,12 @@ static int stk8312_probe(struct i2c_client *client,
return ret;
}
data->sample_rate_idx = STK8312_SR_400HZ_IDX;
- ret = stk8312_set_range(data, 1);
+ ret = stk8312_set_range(data, STK8312_RNG_6G);
if (ret < 0)
return ret;
- ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE);
+ ret = stk8312_set_mode(data,
+ STK8312_MODE_INT_AH_PP | STK8312_MODE_ACTIVE);
if (ret < 0)
return ret;
@@ -606,7 +620,7 @@ static int stk8312_probe(struct i2c_client *client,
goto err_buffer_cleanup;
}
- return ret;
+ return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
@@ -662,6 +676,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = {
{"STK8312", 0},
{}
};
+MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id);
static const struct acpi_device_id stk8312_acpi_id[] = {
{"STK8312", 0},
@@ -672,7 +687,7 @@ MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
static struct i2c_driver stk8312_driver = {
.driver = {
- .name = "stk8312",
+ .name = STK8312_DRIVER_NAME,
.pm = STK8312_PM_OPS,
.acpi_match_table = ACPI_PTR(stk8312_acpi_id),
},
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 16cee637109b..80f77d8704b5 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -572,6 +572,7 @@ static const struct i2c_device_id stk8ba50_i2c_id[] = {
{"stk8ba50", 0},
{}
};
+MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id);
static const struct acpi_device_id stk8ba50_acpi_id[] = {
{"STK8BA50", 0},
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 233d47b7dea8..50c103d75af9 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -228,8 +228,8 @@ config MCP320X
depends on SPI
help
Say yes here to build support for Microchip Technology's
- MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or
- MCP3208 analog to digital converter.
+ MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204,
+ MCP3208 or MCP3301 analog to digital converter.
This driver can also be built as a module. If so, the module will be
called mcp320x.
diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c
index aecc9ad995ad..4946d9bf1764 100644
--- a/drivers/iio/adc/berlin2-adc.c
+++ b/drivers/iio/adc/berlin2-adc.c
@@ -26,7 +26,7 @@
#define BERLIN2_SM_CTRL 0x14
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
-#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */
+#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */
#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
@@ -53,14 +53,14 @@
#define BERLIN2_SM_ADC_MASK 0x3ff
#define BERLIN2_SM_ADC_STATUS 0x1c
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
-#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf
+#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0)
#define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */
-#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16)
+#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16)
#define BERLIN2_SM_TSEN_STATUS 0x24
#define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0)
#define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1)
#define BERLIN2_SM_TSEN_DATA 0x28
-#define BERLIN2_SM_TSEN_MASK 0xfff
+#define BERLIN2_SM_TSEN_MASK GENMASK(9, 0)
#define BERLIN2_SM_TSEN_CTRL 0x74
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
@@ -86,7 +86,7 @@ struct berlin2_adc_priv {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
-static struct iio_chan_spec berlin2_adc_channels[] = {
+static const struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */
@@ -103,7 +103,6 @@ static struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */
IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */
};
-#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels)
static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
{
@@ -221,7 +220,7 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
return temp;
if (temp > 2047)
- temp = -(4096 - temp);
+ temp -= 4096;
/* Convert to milli Celsius */
*val = ((temp * 100000) / 264 - 270000);
@@ -286,8 +285,7 @@ static int berlin2_adc_probe(struct platform_device *pdev)
int irq, tsen_irq;
int ret;
- indio_dev = devm_iio_device_alloc(&pdev->dev,
- sizeof(struct berlin2_adc_priv));
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
@@ -301,11 +299,11 @@ static int berlin2_adc_probe(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, "adc");
if (irq < 0)
- return -ENODEV;
+ return irq;
tsen_irq = platform_get_irq_byname(pdev, "tsen");
if (tsen_irq < 0)
- return -ENODEV;
+ return tsen_irq;
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
pdev->dev.driver->name, indio_dev);
@@ -325,8 +323,8 @@ static int berlin2_adc_probe(struct platform_device *pdev)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &berlin2_adc_info;
- indio_dev->num_channels = BERLIN2_N_CHANNELS;
indio_dev->channels = berlin2_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels);
/* Power up the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
index d819823f7257..b19e4f9d16e0 100644
--- a/drivers/iio/adc/mcp320x.c
+++ b/drivers/iio/adc/mcp320x.c
@@ -25,6 +25,7 @@
* http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201
* 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
*
* 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
@@ -47,6 +48,7 @@ enum {
mcp3202,
mcp3204,
mcp3208,
+ mcp3301,
};
struct mcp320x_chip_info {
@@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index,
switch (device_index) {
case mcp3001:
case mcp3201:
+ case mcp3301:
return 0;
case mcp3002:
case mcp3202:
@@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
adc->tx_buf = mcp320x_channel_to_tx_data(device_index,
channel, differential);
- if (device_index != mcp3001 && device_index != mcp3201) {
+ if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) {
ret = spi_sync(adc->spi, &adc->msg);
if (ret < 0)
return ret;
@@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
case mcp3204:
case mcp3208:
return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4);
+ case mcp3301:
+ return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12);
default:
return -EINVAL;
}
@@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
.num_channels = ARRAY_SIZE(mcp3208_channels),
.resolution = 12
},
+ [mcp3301] = {
+ .channels = mcp3201_channels,
+ .num_channels = ARRAY_SIZE(mcp3201_channels),
+ .resolution = 13
+ },
};
static int mcp320x_probe(struct spi_device *spi)
@@ -369,6 +379,9 @@ static const struct of_device_id mcp320x_dt_ids[] = {
.compatible = "mcp3208",
.data = &mcp320x_chip_infos[mcp3208],
}, {
+ .compatible = "mcp3301",
+ .data = &mcp320x_chip_infos[mcp3301],
+ }, {
}
};
MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
@@ -383,6 +396,7 @@ static const struct spi_device_id mcp320x_id[] = {
{ "mcp3202", mcp3202 },
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
+ { "mcp3301", mcp3301 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 819632bf1fda..6bf4c20eb231 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -68,6 +68,9 @@
#define VF610_ADC_CLK_DIV8 0x60
#define VF610_ADC_CLK_MASK 0x60
#define VF610_ADC_ADLSMP_LONG 0x10
+#define VF610_ADC_ADSTS_SHORT 0x100
+#define VF610_ADC_ADSTS_NORMAL 0x200
+#define VF610_ADC_ADSTS_LONG 0x300
#define VF610_ADC_ADSTS_MASK 0x300
#define VF610_ADC_ADLPC_EN 0x80
#define VF610_ADC_ADHSC_EN 0x400
@@ -98,6 +101,8 @@
#define VF610_ADC_CALF 0x2
#define VF610_ADC_TIMEOUT msecs_to_jiffies(100)
+#define DEFAULT_SAMPLE_TIME 1000
+
enum clk_sel {
VF610_ADCIOC_BUSCLK_SET,
VF610_ADCIOC_ALTCLK_SET,
@@ -124,6 +129,17 @@ enum conversion_mode_sel {
VF610_ADC_CONV_LOW_POWER,
};
+enum lst_adder_sel {
+ VF610_ADCK_CYCLES_3,
+ VF610_ADCK_CYCLES_5,
+ VF610_ADCK_CYCLES_7,
+ VF610_ADCK_CYCLES_9,
+ VF610_ADCK_CYCLES_13,
+ VF610_ADCK_CYCLES_17,
+ VF610_ADCK_CYCLES_21,
+ VF610_ADCK_CYCLES_25,
+};
+
struct vf610_adc_feature {
enum clk_sel clk_sel;
enum vol_ref vol_ref;
@@ -132,6 +148,8 @@ struct vf610_adc_feature {
int clk_div;
int sample_rate;
int res_mode;
+ u32 lst_adder_index;
+ u32 default_sample_time;
bool calibration;
bool ovwren;
@@ -155,11 +173,13 @@ struct vf610_adc {
};
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
+static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 };
static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
{
struct vf610_adc_feature *adc_feature = &info->adc_feature;
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
+ u32 adck_period, lst_addr_min;
int divisor, i;
adck_rate = info->max_adck_rate[adc_feature->conv_mode];
@@ -174,6 +194,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
}
/*
+ * Determine the long sample time adder value to be used based
+ * on the default minimum sample time provided.
+ */
+ adck_period = NSEC_PER_SEC / adck_rate;
+ lst_addr_min = adc_feature->default_sample_time / adck_period;
+ for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) {
+ if (vf610_lst_adder[i] > lst_addr_min) {
+ adc_feature->lst_adder_index = i;
+ break;
+ }
+ }
+
+ /*
* Calculate ADC sample frequencies
* Sample time unit is ADCK cycles. ADCK clk source is ipg clock,
* which is the same as bus clock.
@@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
* SFCAdder: fixed to 6 ADCK cycles
* AverageNum: 1, 4, 8, 16, 32 samples for hardware average.
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
- * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles
+ * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
*/
adck_rate = ipg_rate / info->adc_feature.clk_div;
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
info->sample_freq_avail[i] =
- adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3));
+ adck_rate / (6 + vf610_hw_avgs[i] *
+ (25 + vf610_lst_adder[adc_feature->lst_adder_index]));
}
static inline void vf610_adc_cfg_init(struct vf610_adc *info)
@@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info)
break;
}
- /* Use the short sample mode */
- cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK);
+ /*
+ * Set ADLSMP and ADSTS based on the Long Sample Time Adder value
+ * determined.
+ */
+ switch (adc_feature->lst_adder_index) {
+ case VF610_ADCK_CYCLES_3:
+ break;
+ case VF610_ADCK_CYCLES_5:
+ cfg_data |= VF610_ADC_ADSTS_SHORT;
+ break;
+ case VF610_ADCK_CYCLES_7:
+ cfg_data |= VF610_ADC_ADSTS_NORMAL;
+ break;
+ case VF610_ADCK_CYCLES_9:
+ cfg_data |= VF610_ADC_ADSTS_LONG;
+ break;
+ case VF610_ADCK_CYCLES_13:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ break;
+ case VF610_ADCK_CYCLES_17:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ cfg_data |= VF610_ADC_ADSTS_SHORT;
+ break;
+ case VF610_ADCK_CYCLES_21:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ cfg_data |= VF610_ADC_ADSTS_NORMAL;
+ break;
+ case VF610_ADCK_CYCLES_25:
+ cfg_data |= VF610_ADC_ADLSMP_LONG;
+ cfg_data |= VF610_ADC_ADSTS_NORMAL;
+ break;
+ default:
+ dev_err(info->dev, "error in sample time select\n");
+ }
/* update hardware average selection */
cfg_data &= ~VF610_ADC_AVGS_MASK;
@@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev)
of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
info->max_adck_rate, 3);
+ ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time",
+ &info->adc_feature.default_sample_time);
+ if (ret)
+ info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME;
+
platform_set_drvdata(pdev, indio_dev);
init_completion(&info->completion);
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index 8086cbcff87d..2e7fdb502645 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -126,6 +126,9 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
int err, i = 0;
struct st_sensor_data *sdata = iio_priv(indio_dev);
+ if (sdata->sensor_settings->fs.addr == 0)
+ return 0;
+
err = st_sensors_match_fs(sdata->sensor_settings, fs, &i);
if (err < 0)
goto st_accel_set_fullscale_error;
@@ -479,46 +482,43 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
int num_sensors_list,
const struct st_sensor_settings *sensor_settings)
{
- u8 wai;
int i, n, err;
+ u8 wai;
struct st_sensor_data *sdata = iio_priv(indio_dev);
- err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
- ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
- if (err < 0) {
- dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
- goto read_wai_error;
- }
-
for (i = 0; i < num_sensors_list; i++) {
- if (sensor_settings[i].wai == wai)
+ for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
+ if (strcmp(indio_dev->name,
+ sensor_settings[i].sensors_supported[n]) == 0) {
+ break;
+ }
+ }
+ if (n < ST_SENSORS_MAX_4WAI)
break;
}
- if (i == num_sensors_list)
- goto device_not_supported;
+ if (i == num_sensors_list) {
+ dev_err(&indio_dev->dev, "device name %s not recognized.\n",
+ indio_dev->name);
+ return -ENODEV;
+ }
- for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) {
- if (strcmp(indio_dev->name,
- &sensor_settings[i].sensors_supported[n][0]) == 0)
- break;
+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
+ sensor_settings[i].wai_addr, &wai);
+ if (err < 0) {
+ dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
+ return err;
}
- if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) {
- dev_err(&indio_dev->dev, "device name \"%s\" and WhoAmI (0x%02x) mismatch",
- indio_dev->name, wai);
- goto sensor_name_mismatch;
+
+ if (sensor_settings[i].wai != wai) {
+ dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n",
+ indio_dev->name, wai);
+ return -EINVAL;
}
sdata->sensor_settings =
(struct st_sensor_settings *)&sensor_settings[i];
return i;
-
-device_not_supported:
- dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
-sensor_name_mismatch:
- err = -ENODEV;
-read_wai_error:
- return err;
}
EXPORT_SYMBOL(st_sensors_check_device_support);
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig
index b3d0e94f72eb..8d2439345673 100644
--- a/drivers/iio/gyro/Kconfig
+++ b/drivers/iio/gyro/Kconfig
@@ -53,7 +53,8 @@ config ADXRS450
config BMG160
tristate "BOSCH BMG160 Gyro Sensor"
depends on I2C
- select IIO_TRIGGERED_BUFFER if IIO_BUFFER
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor
driver. This driver also supports BMI055 gyroscope.
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 591bd555e1f3..26de876b223d 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -473,6 +473,7 @@ enum adis16136_id {
ID_ADIS16133,
ID_ADIS16135,
ID_ADIS16136,
+ ID_ADIS16137,
};
static const struct adis16136_chip_info adis16136_chip_info[] = {
@@ -488,6 +489,10 @@ static const struct adis16136_chip_info adis16136_chip_info[] = {
.precision = IIO_DEGREE_TO_RAD(450),
.fullscale = 24623,
},
+ [ID_ADIS16137] = {
+ .precision = IIO_DEGREE_TO_RAD(1000),
+ .fullscale = 24609,
+ },
};
static int adis16136_probe(struct spi_device *spi)
@@ -557,6 +562,7 @@ static const struct spi_device_id adis16136_ids[] = {
{ "adis16133", ID_ADIS16133 },
{ "adis16135", ID_ADIS16135 },
{ "adis16136", ID_ADIS16136 },
+ { "adis16137", ID_ADIS16137 },
{ }
};
MODULE_DEVICE_TABLE(spi, adis16136_ids);
diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c
index 75fe0edd3d0f..00c6ad9bf35f 100644
--- a/drivers/iio/gyro/adis16260.c
+++ b/drivers/iio/gyro/adis16260.c
@@ -101,19 +101,24 @@
#define ADIS16260_SCAN_TEMP 3
#define ADIS16260_SCAN_ANGL 4
-/* Power down the device */
-static int adis16260_stop_device(struct iio_dev *indio_dev)
-{
- struct adis *adis = iio_priv(indio_dev);
- int ret;
- u16 val = ADIS16260_SLP_CNT_POWER_OFF;
+struct adis16260_chip_info {
+ unsigned int gyro_max_val;
+ unsigned int gyro_max_scale;
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
- ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val);
- if (ret)
- dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
+struct adis16260 {
+ const struct adis16260_chip_info *info;
- return ret;
-}
+ struct adis adis;
+};
+
+enum adis16260_type {
+ ADIS16251,
+ ADIS16260,
+ ADIS16266,
+};
static const struct iio_chan_spec adis16260_channels[] = {
ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
@@ -131,6 +136,55 @@ static const struct iio_chan_spec adis16260_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(5),
};
+static const struct iio_chan_spec adis16266_channels[] = {
+ ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO,
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), 14),
+ ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP,
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
+ ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY,
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
+ ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC,
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), 12),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const struct adis16260_chip_info adis16260_chip_info_table[] = {
+ [ADIS16251] = {
+ .gyro_max_scale = 80,
+ .gyro_max_val = IIO_RAD_TO_DEGREE(4368),
+ .channels = adis16260_channels,
+ .num_channels = ARRAY_SIZE(adis16260_channels),
+ },
+ [ADIS16260] = {
+ .gyro_max_scale = 320,
+ .gyro_max_val = IIO_RAD_TO_DEGREE(4368),
+ .channels = adis16260_channels,
+ .num_channels = ARRAY_SIZE(adis16260_channels),
+ },
+ [ADIS16266] = {
+ .gyro_max_scale = 14000,
+ .gyro_max_val = IIO_RAD_TO_DEGREE(3357),
+ .channels = adis16266_channels,
+ .num_channels = ARRAY_SIZE(adis16266_channels),
+ },
+};
+
+/* Power down the device */
+static int adis16260_stop_device(struct iio_dev *indio_dev)
+{
+ struct adis16260 *adis16260 = iio_priv(indio_dev);
+ int ret;
+ u16 val = ADIS16260_SLP_CNT_POWER_OFF;
+
+ ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val);
+ if (ret)
+ dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT");
+
+ return ret;
+}
+
static const u8 adis16260_addresses[][2] = {
[ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE },
};
@@ -140,7 +194,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
int *val, int *val2,
long mask)
{
- struct adis *adis = iio_priv(indio_dev);
+ struct adis16260 *adis16260 = iio_priv(indio_dev);
+ const struct adis16260_chip_info *info = adis16260->info;
+ struct adis *adis = &adis16260->adis;
int ret;
u8 addr;
s16 val16;
@@ -152,15 +208,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
- *val = 0;
- if (spi_get_device_id(adis->spi)->driver_data) {
- /* 0.01832 degree / sec */
- *val2 = IIO_DEGREE_TO_RAD(18320);
- } else {
- /* 0.07326 degree / sec */
- *val2 = IIO_DEGREE_TO_RAD(73260);
- }
- return IIO_VAL_INT_PLUS_MICRO;
+ *val = info->gyro_max_scale;
+ *val2 = info->gyro_max_val;
+ return IIO_VAL_FRACTIONAL;
case IIO_INCLI:
*val = 0;
*val2 = IIO_DEGREE_TO_RAD(36630);
@@ -224,7 +274,8 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
int val2,
long mask)
{
- struct adis *adis = iio_priv(indio_dev);
+ struct adis16260 *adis16260 = iio_priv(indio_dev);
+ struct adis *adis = &adis16260->adis;
int ret;
u8 addr;
u8 t;
@@ -305,35 +356,42 @@ static const struct adis_data adis16260_data = {
static int adis16260_probe(struct spi_device *spi)
{
+ const struct spi_device_id *id;
+ struct adis16260 *adis16260;
struct iio_dev *indio_dev;
- struct adis *adis;
int ret;
+ id = spi_get_device_id(spi);
+ if (!id)
+ return -ENODEV;
+
/* setup the industrialio driver allocated elements */
- indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260));
if (!indio_dev)
return -ENOMEM;
- adis = iio_priv(indio_dev);
+ adis16260 = iio_priv(indio_dev);
/* this is only used for removal purposes */
spi_set_drvdata(spi, indio_dev);
- indio_dev->name = spi_get_device_id(spi)->name;
+ adis16260->info = &adis16260_chip_info_table[id->driver_data];
+
+ indio_dev->name = id->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adis16260_info;
- indio_dev->channels = adis16260_channels;
- indio_dev->num_channels = ARRAY_SIZE(adis16260_channels);
+ indio_dev->channels = adis16260->info->channels;
+ indio_dev->num_channels = adis16260->info->num_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = adis_init(adis, indio_dev, spi, &adis16260_data);
+ ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data);
if (ret)
return ret;
- ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL);
+ ret = adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL);
if (ret)
return ret;
/* Get the device into a sane initial state */
- ret = adis_initial_startup(adis);
+ ret = adis_initial_startup(&adis16260->adis);
if (ret)
goto error_cleanup_buffer_trigger;
ret = iio_device_register(indio_dev);
@@ -343,18 +401,18 @@ static int adis16260_probe(struct spi_device *spi)
return 0;
error_cleanup_buffer_trigger:
- adis_cleanup_buffer_and_trigger(adis, indio_dev);
+ adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev);
return ret;
}
static int adis16260_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct adis *adis = iio_priv(indio_dev);
+ struct adis16260 *adis16260 = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis16260_stop_device(indio_dev);
- adis_cleanup_buffer_and_trigger(adis, indio_dev);
+ adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev);
return 0;
}
@@ -364,11 +422,12 @@ static int adis16260_remove(struct spi_device *spi)
* support for the on chip filtering.
*/
static const struct spi_device_id adis16260_id[] = {
- {"adis16260", 0},
- {"adis16265", 0},
- {"adis16250", 0},
- {"adis16255", 0},
- {"adis16251", 1},
+ {"adis16260", ADIS16260},
+ {"adis16265", ADIS16260},
+ {"adis16266", ADIS16266},
+ {"adis16250", ADIS16260},
+ {"adis16255", ADIS16260},
+ {"adis16251", ADIS16251},
{}
};
MODULE_DEVICE_TABLE(spi, adis16260_id);
diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c
index ffe96642b6d0..4b993a5bc9a1 100644
--- a/drivers/iio/gyro/st_gyro_core.c
+++ b/drivers/iio/gyro/st_gyro_core.c
@@ -131,6 +131,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = {
static const struct st_sensor_settings st_gyro_sensors_settings[] = {
{
.wai = ST_GYRO_1_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = L3G4200D_GYRO_DEV_NAME,
[1] = LSM330DL_GYRO_DEV_NAME,
@@ -190,6 +191,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
},
{
.wai = ST_GYRO_2_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = L3GD20_GYRO_DEV_NAME,
[1] = LSM330D_GYRO_DEV_NAME,
@@ -252,6 +254,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
},
{
.wai = ST_GYRO_3_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = L3GD20_GYRO_DEV_NAME,
},
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
index 7d79a1ac5f5f..1165b1c4f9d6 100644
--- a/drivers/iio/humidity/dht11.c
+++ b/drivers/iio/humidity/dht11.c
@@ -33,6 +33,7 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
+#include <linux/timekeeping.h>
#include <linux/iio/iio.h>
@@ -46,7 +47,8 @@
* Note that when reading the sensor actually 84 edges are detected, but
* since the last edge is not significant, we only store 83:
*/
-#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
+#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
+ DHT11_EDGES_PREAMBLE + 1)
/* Data transmission timing (nano seconds) */
#define DHT11_START_TRANSMISSION 18 /* ms */
@@ -62,6 +64,7 @@ struct dht11 {
int irq;
struct completion completion;
+ /* The iio sysfs interface doesn't prevent concurrent reads: */
struct mutex lock;
s64 timestamp;
@@ -87,32 +90,20 @@ static unsigned char dht11_decode_byte(int *timing, int threshold)
return ret;
}
-static int dht11_decode(struct dht11 *dht11, int offset)
+static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
{
- int i, t, timing[DHT11_BITS_PER_READ], threshold,
- timeres = DHT11_SENSOR_RESPONSE;
+ int i, t, timing[DHT11_BITS_PER_READ], threshold;
unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
- /* Calculate timestamp resolution */
- for (i = 1; i < dht11->num_edges; ++i) {
- t = dht11->edges[i].ts - dht11->edges[i-1].ts;
- if (t > 0 && t < timeres)
- timeres = t;
- }
- if (2*timeres > DHT11_DATA_BIT_HIGH) {
- pr_err("dht11: timeresolution %d too bad for decoding\n",
- timeres);
- return -EIO;
- }
threshold = DHT11_DATA_BIT_HIGH / timeres;
- if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold)
+ if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold)
pr_err("dht11: WARNING: decoding ambiguous\n");
/* scale down with timeres and check validity */
for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
- t = dht11->edges[offset + 2*i + 2].ts -
- dht11->edges[offset + 2*i + 1].ts;
- if (!dht11->edges[offset + 2*i + 1].value)
+ t = dht11->edges[offset + 2 * i + 2].ts -
+ dht11->edges[offset + 2 * i + 1].ts;
+ if (!dht11->edges[offset + 2 * i + 1].value)
return -EIO; /* lost synchronisation */
timing[i] = t / timeres;
}
@@ -126,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset)
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
return -EIO;
- dht11->timestamp = iio_get_time_ns();
+ dht11->timestamp = ktime_get_real_ns();
if (hum_int < 20) { /* DHT22 */
dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
((temp_int & 0x80) ? -100 : 100);
@@ -154,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
/* TODO: Consider making the handler safe for IRQ sharing */
if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
- dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
+ dht11->edges[dht11->num_edges].ts = ktime_get_real_ns();
dht11->edges[dht11->num_edges++].value =
gpio_get_value(dht11->gpio);
@@ -166,14 +157,26 @@ static irqreturn_t dht11_handle_irq(int irq, void *data)
}
static int dht11_read_raw(struct iio_dev *iio_dev,
- const struct iio_chan_spec *chan,
+ const struct iio_chan_spec *chan,
int *val, int *val2, long m)
{
struct dht11 *dht11 = iio_priv(iio_dev);
- int ret;
+ int ret, timeres;
mutex_lock(&dht11->lock);
- if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
+ if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) {
+ timeres = ktime_get_resolution_ns();
+ if (DHT11_DATA_BIT_HIGH < 2 * timeres) {
+ dev_err(dht11->dev, "timeresolution %dns too low\n",
+ timeres);
+ /* In theory a better clock could become available
+ * at some point ... and there is no error code
+ * that really fits better.
+ */
+ ret = -EAGAIN;
+ goto err;
+ }
+
reinit_completion(&dht11->completion);
dht11->num_edges = 0;
@@ -192,13 +195,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
goto err;
ret = wait_for_completion_killable_timeout(&dht11->completion,
- HZ);
+ HZ);
free_irq(dht11->irq, iio_dev);
if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
dev_err(&iio_dev->dev,
- "Only %d signal edges detected\n",
+ "Only %d signal edges detected\n",
dht11->num_edges);
ret = -ETIMEDOUT;
}
@@ -206,9 +209,10 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
goto err;
ret = dht11_decode(dht11,
- dht11->num_edges == DHT11_EDGES_PER_READ ?
+ dht11->num_edges == DHT11_EDGES_PER_READ ?
DHT11_EDGES_PREAMBLE :
- DHT11_EDGES_PREAMBLE - 2);
+ DHT11_EDGES_PREAMBLE - 2,
+ timeres);
if (ret)
goto err;
}
@@ -261,9 +265,10 @@ static int dht11_probe(struct platform_device *pdev)
dht11 = iio_priv(iio);
dht11->dev = dev;
- dht11->gpio = ret = of_get_gpio(node, 0);
+ ret = of_get_gpio(node, 0);
if (ret < 0)
return ret;
+ dht11->gpio = ret;
ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
if (ret)
return ret;
@@ -274,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev)
return -EINVAL;
}
- dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
+ dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1;
dht11->num_edges = -1;
platform_set_drvdata(pdev, iio);
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index 2fd68f2219a7..abc4c50de9e8 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -139,7 +139,9 @@ enum adis16400_chip_variant {
ADIS16360,
ADIS16362,
ADIS16364,
+ ADIS16367,
ADIS16400,
+ ADIS16445,
ADIS16448,
};
@@ -622,6 +624,17 @@ static const struct iio_chan_spec adis16400_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
};
+static const struct iio_chan_spec adis16445_channels[] = {
+ ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
+ ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
+ ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16),
+ ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16),
+ ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16),
+ ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16),
+ ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
+};
+
static const struct iio_chan_spec adis16448_channels[] = {
ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16),
ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16),
@@ -696,7 +709,8 @@ static struct adis16400_chip_info adis16400_chips[] = {
[ADIS16300] = {
.channels = adis16300_channels,
.num_channels = ARRAY_SIZE(adis16300_channels),
- .flags = ADIS16400_HAS_SLOW_MODE,
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
.gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 5884,
.temp_scale_nano = 140000000, /* 0.14 C */
@@ -763,6 +777,18 @@ static struct adis16400_chip_info adis16400_chips[] = {
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
},
+ [ADIS16367] = {
+ .channels = adis16350_channels,
+ .num_channels = ARRAY_SIZE(adis16350_channels),
+ .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE |
+ ADIS16400_HAS_SERIAL_NUMBER,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
+ .temp_scale_nano = 136000000, /* 0.136 C */
+ .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
+ .set_freq = adis16400_set_freq,
+ .get_freq = adis16400_get_freq,
+ },
[ADIS16400] = {
.channels = adis16400_channels,
.num_channels = ARRAY_SIZE(adis16400_channels),
@@ -774,13 +800,26 @@ static struct adis16400_chip_info adis16400_chips[] = {
.set_freq = adis16400_set_freq,
.get_freq = adis16400_get_freq,
},
+ [ADIS16445] = {
+ .channels = adis16445_channels,
+ .num_channels = ARRAY_SIZE(adis16445_channels),
+ .flags = ADIS16400_HAS_PROD_ID |
+ ADIS16400_HAS_SERIAL_NUMBER |
+ ADIS16400_BURST_DIAG_STAT,
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
+ .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */
+ .temp_scale_nano = 73860000, /* 0.07386 C */
+ .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
+ .set_freq = adis16334_set_freq,
+ .get_freq = adis16334_get_freq,
+ },
[ADIS16448] = {
.channels = adis16448_channels,
.num_channels = ARRAY_SIZE(adis16448_channels),
.flags = ADIS16400_HAS_PROD_ID |
ADIS16400_HAS_SERIAL_NUMBER |
ADIS16400_BURST_DIAG_STAT,
- .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */
+ .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */
.accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */
.temp_scale_nano = 73860000, /* 0.07386 C */
.temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
@@ -926,6 +965,7 @@ static int adis16400_remove(struct spi_device *spi)
static const struct spi_device_id adis16400_id[] = {
{"adis16300", ADIS16300},
+ {"adis16305", ADIS16300},
{"adis16334", ADIS16334},
{"adis16350", ADIS16350},
{"adis16354", ADIS16350},
@@ -934,8 +974,10 @@ static const struct spi_device_id adis16400_id[] = {
{"adis16362", ADIS16362},
{"adis16364", ADIS16364},
{"adis16365", ADIS16360},
+ {"adis16367", ADIS16367},
{"adis16400", ADIS16400},
{"adis16405", ADIS16400},
+ {"adis16445", ADIS16445},
{"adis16448", ADIS16448},
{}
};
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 989605dd6f78..b94bfd3f595b 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -110,6 +110,10 @@
struct adis16480_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
+ unsigned int gyro_max_val;
+ unsigned int gyro_max_scale;
+ unsigned int accel_max_val;
+ unsigned int accel_max_scale;
};
struct adis16480 {
@@ -497,19 +501,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
static int adis16480_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
+ struct adis16480 *st = iio_priv(indio_dev);
+
switch (info) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan, 0, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
- *val = 0;
- *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */
- return IIO_VAL_INT_PLUS_MICRO;
+ *val = st->chip_info->gyro_max_scale;
+ *val2 = st->chip_info->gyro_max_val;
+ return IIO_VAL_FRACTIONAL;
case IIO_ACCEL:
- *val = 0;
- *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */
- return IIO_VAL_INT_PLUS_MICRO;
+ *val = st->chip_info->accel_max_scale;
+ *val2 = st->chip_info->accel_max_val;
+ return IIO_VAL_FRACTIONAL;
case IIO_MAGN:
*val = 0;
*val2 = 100; /* 0.0001 gauss */
@@ -674,18 +680,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
[ADIS16375] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
+ /*
+ * storing the value in rad/degree and the scale in degree
+ * gives us the result in rad and better precession than
+ * storing the scale directly in rad.
+ */
+ .gyro_max_val = IIO_RAD_TO_DEGREE(22887),
+ .gyro_max_scale = 300,
+ .accel_max_val = IIO_M_S_2_TO_G(21973),
+ .accel_max_scale = 18,
},
[ADIS16480] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
+ .gyro_max_val = IIO_RAD_TO_DEGREE(22500),
+ .gyro_max_scale = 450,
+ .accel_max_val = IIO_M_S_2_TO_G(12500),
+ .accel_max_scale = 5,
},
[ADIS16485] = {
.channels = adis16485_channels,
.num_channels = ARRAY_SIZE(adis16485_channels),
+ .gyro_max_val = IIO_RAD_TO_DEGREE(22500),
+ .gyro_max_scale = 450,
+ .accel_max_val = IIO_M_S_2_TO_G(20000),
+ .accel_max_scale = 5,
},
[ADIS16488] = {
.channels = adis16480_channels,
.num_channels = ARRAY_SIZE(adis16480_channels),
+ .gyro_max_val = IIO_RAD_TO_DEGREE(22500),
+ .gyro_max_scale = 450,
+ .accel_max_val = IIO_M_S_2_TO_G(22500),
+ .accel_max_scale = 18,
},
};
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 462a010628cd..82cdf5090fa7 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -1363,7 +1363,7 @@ static int kmx61_probe(struct i2c_client *client,
if (client->irq < 0)
client->irq = kmx61_gpio_probe(client, data);
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kmx61_data_rdy_trig_poll,
kmx61_event_handler,
@@ -1445,10 +1445,10 @@ err_iio_unregister_mag:
err_iio_unregister_acc:
iio_device_unregister(data->acc_indio_dev);
err_buffer_cleanup_mag:
- if (client->irq >= 0)
+ if (client->irq > 0)
iio_triggered_buffer_cleanup(data->mag_indio_dev);
err_buffer_cleanup_acc:
- if (client->irq >= 0)
+ if (client->irq > 0)
iio_triggered_buffer_cleanup(data->acc_indio_dev);
err_trigger_unregister_motion:
iio_trigger_unregister(data->motion_trig);
@@ -1472,7 +1472,7 @@ static int kmx61_remove(struct i2c_client *client)
iio_device_unregister(data->acc_indio_dev);
iio_device_unregister(data->mag_indio_dev);
- if (client->irq >= 0) {
+ if (client->irq > 0) {
iio_triggered_buffer_cleanup(data->acc_indio_dev);
iio_triggered_buffer_cleanup(data->mag_indio_dev);
iio_trigger_unregister(data->acc_dready_trig);
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index f72be48e650c..d7e908acb480 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -91,9 +91,16 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
+ * @filp: File structure pointer for the char device
+ * @buf: Destination buffer for iio buffer read
+ * @n: First n bytes to read
+ * @f_ps: Long offset provided by the user as a seek position
*
* This function relies on all buffer implementations having an
* iio_buffer as their first element.
+ *
+ * Return: negative values corresponding to error codes or ret != 0
+ * for ending the reading activity
**/
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps)
@@ -143,6 +150,12 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
/**
* iio_buffer_poll() - poll the buffer to find out if it has data
+ * @filp: File structure pointer for device access
+ * @wait: Poll table structure pointer for which the driver adds
+ * a wait queue
+ *
+ * Return: (POLLIN | POLLRDNORM) if data is available for reading
+ * or 0 for other cases
*/
unsigned int iio_buffer_poll(struct file *filp,
struct poll_table_struct *wait)
@@ -151,7 +164,7 @@ unsigned int iio_buffer_poll(struct file *filp,
struct iio_buffer *rb = indio_dev->buffer;
if (!indio_dev->info)
- return -ENODEV;
+ return 0;
poll_wait(filp, &rb->pollq, wait);
if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0))
@@ -1136,7 +1149,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev,
EXPORT_SYMBOL_GPL(iio_scan_mask_query);
/**
- * struct iio_demux_table() - table describing demux memcpy ops
+ * struct iio_demux_table - table describing demux memcpy ops
* @from: index to copy from
* @to: index to copy to
* @length: how many bytes to copy
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d8051cdcbdc2..b3fcc2c449d8 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -406,10 +406,16 @@ EXPORT_SYMBOL_GPL(iio_enum_write);
/**
* iio_format_value() - Formats a IIO value into its string representation
- * @buf: The buffer to which the formated value gets written
- * @type: One of the IIO_VAL_... constants. This decides how the val and val2
- * parameters are formatted.
- * @vals: pointer to the values, exact meaning depends on the type parameter.
+ * @buf: The buffer to which the formatted value gets written
+ * @type: One of the IIO_VAL_... constants. This decides how the val
+ * and val2 parameters are formatted.
+ * @size: Number of IIO value entries contained in vals
+ * @vals: Pointer to the values, exact meaning depends on the
+ * type parameter.
+ *
+ * Return: 0 by default, a negative number on failure or the
+ * total number of characters written for a type that belongs
+ * to the IIO_VAL_... constant.
*/
ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
{
@@ -1096,6 +1102,11 @@ EXPORT_SYMBOL_GPL(devm_iio_device_free);
/**
* iio_chrdev_open() - chrdev file open for buffer access and ioctls
+ * @inode: Inode structure for identifying the device in the file system
+ * @filp: File structure for iio device used to keep and later access
+ * private data
+ *
+ * Return: 0 on success or -EBUSY if the device is already opened
**/
static int iio_chrdev_open(struct inode *inode, struct file *filp)
{
@@ -1114,7 +1125,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp)
/**
* iio_chrdev_release() - chrdev file close buffer access and ioctls
- **/
+ * @inode: Inode structure pointer for the char device
+ * @filp: File structure pointer for the char device
+ *
+ * Return: 0 for successful release
+ */
static int iio_chrdev_release(struct inode *inode, struct file *filp)
{
struct iio_dev *indio_dev = container_of(inode->i_cdev,
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 894d8137c4cf..cae332b1d7ea 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -32,6 +32,7 @@
* @dev_attr_list: list of event interface sysfs attribute
* @flags: file operations related flags including busy flag.
* @group: event interface sysfs attribute group
+ * @read_lock: lock to protect kfifo read operations
*/
struct iio_event_interface {
wait_queue_head_t wait;
@@ -75,6 +76,11 @@ EXPORT_SYMBOL(iio_push_event);
/**
* iio_event_poll() - poll the event queue to find out if it has data
+ * @filep: File structure pointer to identify the device
+ * @wait: Poll table pointer to add the wait queue on
+ *
+ * Return: (POLLIN | POLLRDNORM) if data is available for reading
+ * or a negative error code on failure
*/
static unsigned int iio_event_poll(struct file *filep,
struct poll_table_struct *wait)
@@ -84,7 +90,7 @@ static unsigned int iio_event_poll(struct file *filep,
unsigned int events = 0;
if (!indio_dev->info)
- return -ENODEV;
+ return events;
poll_wait(filep, &ev_int->wait, wait);
diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index d31098e0c43f..570606c2adbd 100644
--- a/drivers/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -40,7 +40,14 @@ static DEFINE_MUTEX(iio_trigger_list_lock);
/**
* iio_trigger_read_name() - retrieve useful identifying name
- **/
+ * @dev: device associated with the iio_trigger
+ * @attr: pointer to the device_attribute structure that is
+ * being processed
+ * @buf: buffer to print the name into
+ *
+ * Return: a negative number on failure or the number of written
+ * characters on success.
+ */
static ssize_t iio_trigger_read_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -288,10 +295,17 @@ EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc);
/**
* iio_trigger_read_current() - trigger consumer sysfs query current trigger
+ * @dev: device associated with an industrial I/O device
+ * @attr: pointer to the device_attribute structure that
+ * is being processed
+ * @buf: buffer where the current trigger name will be printed into
*
* For trigger consumers the current_trigger interface allows the trigger
* used by the device to be queried.
- **/
+ *
+ * Return: a negative number on failure, the number of characters written
+ * on success or 0 if no trigger is available
+ */
static ssize_t iio_trigger_read_current(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -305,11 +319,18 @@ static ssize_t iio_trigger_read_current(struct device *dev,
/**
* iio_trigger_write_current() - trigger consumer sysfs set current trigger
+ * @dev: device associated with an industrial I/O device
+ * @attr: device attribute that is being processed
+ * @buf: string buffer that holds the name of the trigger
+ * @len: length of the trigger name held by buf
*
* For trigger consumers the current_trigger interface allows the trigger
* used for this device to be specified at run time based on the trigger's
* name.
- **/
+ *
+ * Return: negative error code on failure or length of the buffer
+ * on success
+ */
static ssize_t iio_trigger_write_current(struct device *dev,
struct device_attribute *attr,
const char *buf,
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index b37e18d07630..7ed859a700c4 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -210,6 +210,27 @@ config LTR501
This driver can also be built as a module. If so, the module
will be called ltr501.
+config OPT3001
+ tristate "Texas Instruments OPT3001 Light Sensor"
+ depends on I2C
+ help
+ If you say Y or M here, you get support for Texas Instruments
+ OPT3001 Ambient Light Sensor.
+
+ If built as a dynamically linked module, it will be called
+ opt3001.
+
+config PA12203001
+ tristate "TXC PA12203001 light and proximity sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the TXC PA12203001
+ ambient light and proximity sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called pa12203001.
+
config STK3310
tristate "STK3310 ALS and proximity sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index adf97237db72..91c74c014b6f 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -19,6 +19,8 @@ obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
+obj-$(CONFIG_OPT3001) += opt3001.o
+obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_STK3310) += stk3310.o
diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c
index 1dafa0756bfa..60537ec0c923 100644
--- a/drivers/iio/light/acpi-als.c
+++ b/drivers/iio/light/acpi-als.c
@@ -65,20 +65,20 @@ static const struct iio_chan_spec acpi_als_channels[] = {
* to acpi_als_channels[], the evt_buffer below will grow
* automatically.
*/
-#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
-#define EVT_BUFFER_SIZE \
- (sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32)))
+#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
+#define ACPI_ALS_EVT_BUFFER_SIZE \
+ (sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32)))
struct acpi_als {
struct acpi_device *device;
struct mutex lock;
- s32 evt_buffer[EVT_BUFFER_SIZE];
+ s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE];
};
/*
* All types of properties the ACPI0008 block can report. The ALI, ALC, ALT
- * and ALP can all be handled by als_read_value() below, while the ALR is
+ * and ALP can all be handled by acpi_als_read_value() below, while the ALR is
* special.
*
* The _ALR property returns tables that can be used to fine-tune the values
@@ -93,7 +93,7 @@ struct acpi_als {
#define ACPI_ALS_POLLING "_ALP"
#define ACPI_ALS_TABLES "_ALR"
-static int als_read_value(struct acpi_als *als, char *prop, s32 *val)
+static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val)
{
unsigned long long temp_val;
acpi_status status;
@@ -122,11 +122,11 @@ static void acpi_als_notify(struct acpi_device *device, u32 event)
mutex_lock(&als->lock);
- memset(buffer, 0, EVT_BUFFER_SIZE);
+ memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE);
switch (event) {
case ACPI_ALS_NOTIFY_ILLUMINANCE:
- ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
+ ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
if (ret < 0)
goto out;
*buffer++ = val;
@@ -159,7 +159,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev,
if (chan->type != IIO_LIGHT)
return -EINVAL;
- ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
+ ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
if (ret < 0)
return ret;
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 1c0de2f8885d..d6fd0dace74f 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -353,6 +353,7 @@ static const struct of_device_id cm32181_of_match[] = {
{ .compatible = "capella,cm32181" },
{ }
};
+MODULE_DEVICE_TABLE(of, cm32181_of_match);
static struct i2c_driver cm32181_driver = {
.driver = {
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index 1b508c65877c..fe89b6823217 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -417,6 +417,7 @@ static const struct of_device_id cm3232_of_match[] = {
{.compatible = "capella,cm3232"},
{}
};
+MODULE_DEVICE_TABLE(of, cm3232_of_match);
static struct i2c_driver cm3232_driver = {
.driver = {
diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c
index 2a39e141e90c..c8d7b5ea7e78 100644
--- a/drivers/iio/light/cm36651.c
+++ b/drivers/iio/light/cm36651.c
@@ -731,6 +731,7 @@ static const struct of_device_id cm36651_of_match[] = {
{ .compatible = "capella,cm36651" },
{ }
};
+MODULE_DEVICE_TABLE(of, cm36651_of_match);
static struct i2c_driver cm36651_driver = {
.driver = {
diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c
index 0334a814b5eb..6d41086f7c64 100644
--- a/drivers/iio/light/gp2ap020a00f.c
+++ b/drivers/iio/light/gp2ap020a00f.c
@@ -1634,6 +1634,7 @@ static const struct of_device_id gp2ap020a00f_of_match[] = {
{ .compatible = "sharp,gp2ap020a00f" },
{ }
};
+MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);
#endif
static struct i2c_driver gp2ap020a00f_driver = {
diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c
new file mode 100644
index 000000000000..923aa6aef0ed
--- /dev/null
+++ b/drivers/iio/light/opt3001.c
@@ -0,0 +1,804 @@
+/**
+ * opt3001.c - Texas Instruments OPT3001 Light Sensor
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Andreas Dannenberg <dannenberg@ti.com>
+ * Based on previous work from: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 of the License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define OPT3001_RESULT 0x00
+#define OPT3001_CONFIGURATION 0x01
+#define OPT3001_LOW_LIMIT 0x02
+#define OPT3001_HIGH_LIMIT 0x03
+#define OPT3001_MANUFACTURER_ID 0x7e
+#define OPT3001_DEVICE_ID 0x7f
+
+#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12)
+#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12)
+
+#define OPT3001_CONFIGURATION_CT BIT(11)
+
+#define OPT3001_CONFIGURATION_M_MASK (3 << 9)
+#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9)
+#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9)
+#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */
+
+#define OPT3001_CONFIGURATION_OVF BIT(8)
+#define OPT3001_CONFIGURATION_CRF BIT(7)
+#define OPT3001_CONFIGURATION_FH BIT(6)
+#define OPT3001_CONFIGURATION_FL BIT(5)
+#define OPT3001_CONFIGURATION_L BIT(4)
+#define OPT3001_CONFIGURATION_POL BIT(3)
+#define OPT3001_CONFIGURATION_ME BIT(2)
+
+#define OPT3001_CONFIGURATION_FC_MASK (3 << 0)
+
+/* The end-of-conversion enable is located in the low-limit register */
+#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000
+
+#define OPT3001_REG_EXPONENT(n) ((n) >> 12)
+#define OPT3001_REG_MANTISSA(n) ((n) & 0xfff)
+
+/*
+ * Time to wait for conversion result to be ready. The device datasheet
+ * worst-case max value is 880ms. Add some slack to be on the safe side.
+ */
+#define OPT3001_RESULT_READY_TIMEOUT msecs_to_jiffies(1000)
+
+struct opt3001 {
+ struct i2c_client *client;
+ struct device *dev;
+
+ struct mutex lock;
+ u16 ok_to_ignore_lock:1;
+ u16 result_ready:1;
+ wait_queue_head_t result_ready_queue;
+ u16 result;
+
+ u32 int_time;
+ u32 mode;
+
+ u16 high_thresh_mantissa;
+ u16 low_thresh_mantissa;
+
+ u8 high_thresh_exp;
+ u8 low_thresh_exp;
+};
+
+struct opt3001_scale {
+ int val;
+ int val2;
+};
+
+static const struct opt3001_scale opt3001_scales[] = {
+ {
+ .val = 40,
+ .val2 = 950000,
+ },
+ {
+ .val = 81,
+ .val2 = 900000,
+ },
+ {
+ .val = 163,
+ .val2 = 800000,
+ },
+ {
+ .val = 327,
+ .val2 = 600000,
+ },
+ {
+ .val = 655,
+ .val2 = 200000,
+ },
+ {
+ .val = 1310,
+ .val2 = 400000,
+ },
+ {
+ .val = 2620,
+ .val2 = 800000,
+ },
+ {
+ .val = 5241,
+ .val2 = 600000,
+ },
+ {
+ .val = 10483,
+ .val2 = 200000,
+ },
+ {
+ .val = 20966,
+ .val2 = 400000,
+ },
+ {
+ .val = 83865,
+ .val2 = 600000,
+ },
+};
+
+static int opt3001_find_scale(const struct opt3001 *opt, int val,
+ int val2, u8 *exponent)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) {
+ const struct opt3001_scale *scale = &opt3001_scales[i];
+
+ /*
+ * Combine the integer and micro parts for comparison
+ * purposes. Use milli lux precision to avoid 32-bit integer
+ * overflows.
+ */
+ if ((val * 1000 + val2 / 1000) <=
+ (scale->val * 1000 + scale->val2 / 1000)) {
+ *exponent = i;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent,
+ u16 mantissa, int *val, int *val2)
+{
+ int lux;
+
+ lux = 10 * (mantissa << exponent);
+ *val = lux / 1000;
+ *val2 = (lux - (*val * 1000)) * 1000;
+}
+
+static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode)
+{
+ *reg &= ~OPT3001_CONFIGURATION_M_MASK;
+ *reg |= mode;
+ opt->mode = mode;
+}
+
+static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.8");
+
+static struct attribute *opt3001_attributes[] = {
+ &iio_const_attr_integration_time_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group opt3001_attribute_group = {
+ .attrs = opt3001_attributes,
+};
+
+static const struct iio_event_spec opt3001_event_spec[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static const struct iio_chan_spec opt3001_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ .event_spec = opt3001_event_spec,
+ .num_event_specs = ARRAY_SIZE(opt3001_event_spec),
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(1),
+};
+
+static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2)
+{
+ int ret;
+ u16 mantissa;
+ u16 reg;
+ u8 exponent;
+ u16 value;
+
+ /*
+ * Enable the end-of-conversion interrupt mechanism. Note that doing
+ * so will overwrite the low-level limit value however we will restore
+ * this value later on.
+ */
+ ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT,
+ OPT3001_LOW_LIMIT_EOC_ENABLE);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n",
+ OPT3001_LOW_LIMIT);
+ return ret;
+ }
+
+ /* Reset data-ready indicator flag (will be set in the IRQ routine) */
+ opt->result_ready = false;
+
+ /* Allow IRQ to access the device despite lock being set */
+ opt->ok_to_ignore_lock = true;
+
+ /* Configure for single-conversion mode and start a new conversion */
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ goto err;
+ }
+
+ reg = ret;
+ opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SINGLE);
+
+ ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
+ reg);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+ goto err;
+ }
+
+ /* Wait for the IRQ to indicate the conversion is complete */
+ ret = wait_event_timeout(opt->result_ready_queue, opt->result_ready,
+ OPT3001_RESULT_READY_TIMEOUT);
+
+err:
+ /* Disallow IRQ to access the device while lock is active */
+ opt->ok_to_ignore_lock = false;
+
+ if (ret == 0)
+ return -ETIMEDOUT;
+ else if (ret < 0)
+ return ret;
+
+ /*
+ * Disable the end-of-conversion interrupt mechanism by restoring the
+ * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note
+ * that selectively clearing those enable bits would affect the actual
+ * limit value due to bit-overlap and therefore can't be done.
+ */
+ value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa;
+ ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT,
+ value);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n",
+ OPT3001_LOW_LIMIT);
+ return ret;
+ }
+
+ exponent = OPT3001_REG_EXPONENT(opt->result);
+ mantissa = OPT3001_REG_MANTISSA(opt->result);
+
+ opt3001_to_iio_ret(opt, exponent, mantissa, val, val2);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2)
+{
+ *val = 0;
+ *val2 = opt->int_time;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int opt3001_set_int_time(struct opt3001 *opt, int time)
+{
+ int ret;
+ u16 reg;
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
+ }
+
+ reg = ret;
+
+ switch (time) {
+ case 100000:
+ reg &= ~OPT3001_CONFIGURATION_CT;
+ opt->int_time = 100000;
+ break;
+ case 800000:
+ reg |= OPT3001_CONFIGURATION_CT;
+ opt->int_time = 800000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
+ reg);
+}
+
+static int opt3001_read_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ struct opt3001 *opt = iio_priv(iio);
+ int ret;
+
+ if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
+ return -EBUSY;
+
+ if (chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ mutex_lock(&opt->lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = opt3001_get_lux(opt, val, val2);
+ break;
+ case IIO_CHAN_INFO_INT_TIME:
+ ret = opt3001_get_int_time(opt, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&opt->lock);
+
+ return ret;
+}
+
+static int opt3001_write_raw(struct iio_dev *iio,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct opt3001 *opt = iio_priv(iio);
+ int ret;
+
+ if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
+ return -EBUSY;
+
+ if (chan->type != IIO_LIGHT)
+ return -EINVAL;
+
+ if (mask != IIO_CHAN_INFO_INT_TIME)
+ return -EINVAL;
+
+ if (val != 0)
+ return -EINVAL;
+
+ mutex_lock(&opt->lock);
+ ret = opt3001_set_int_time(opt, val2);
+ mutex_unlock(&opt->lock);
+
+ return ret;
+}
+
+static int opt3001_read_event_value(struct iio_dev *iio,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct opt3001 *opt = iio_priv(iio);
+ int ret = IIO_VAL_INT_PLUS_MICRO;
+
+ mutex_lock(&opt->lock);
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ opt3001_to_iio_ret(opt, opt->high_thresh_exp,
+ opt->high_thresh_mantissa, val, val2);
+ break;
+ case IIO_EV_DIR_FALLING:
+ opt3001_to_iio_ret(opt, opt->low_thresh_exp,
+ opt->low_thresh_mantissa, val, val2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&opt->lock);
+
+ return ret;
+}
+
+static int opt3001_write_event_value(struct iio_dev *iio,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, enum iio_event_info info,
+ int val, int val2)
+{
+ struct opt3001 *opt = iio_priv(iio);
+ int ret;
+
+ u16 mantissa;
+ u16 value;
+ u16 reg;
+
+ u8 exponent;
+
+ if (val < 0)
+ return -EINVAL;
+
+ mutex_lock(&opt->lock);
+
+ ret = opt3001_find_scale(opt, val, val2, &exponent);
+ if (ret < 0) {
+ dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2);
+ goto err;
+ }
+
+ mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent;
+ value = (exponent << 12) | mantissa;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ reg = OPT3001_HIGH_LIMIT;
+ opt->high_thresh_mantissa = mantissa;
+ opt->high_thresh_exp = exponent;
+ break;
+ case IIO_EV_DIR_FALLING:
+ reg = OPT3001_LOW_LIMIT;
+ opt->low_thresh_mantissa = mantissa;
+ opt->low_thresh_exp = exponent;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = i2c_smbus_write_word_swapped(opt->client, reg, value);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n", reg);
+ goto err;
+ }
+
+err:
+ mutex_unlock(&opt->lock);
+
+ return ret;
+}
+
+static int opt3001_read_event_config(struct iio_dev *iio,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct opt3001 *opt = iio_priv(iio);
+
+ return opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS;
+}
+
+static int opt3001_write_event_config(struct iio_dev *iio,
+ const struct iio_chan_spec *chan, enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct opt3001 *opt = iio_priv(iio);
+ int ret;
+ u16 mode;
+ u16 reg;
+
+ if (state && opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS)
+ return 0;
+
+ if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN)
+ return 0;
+
+ mutex_lock(&opt->lock);
+
+ mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS
+ : OPT3001_CONFIGURATION_M_SHUTDOWN;
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ goto err;
+ }
+
+ reg = ret;
+ opt3001_set_mode(opt, &reg, mode);
+
+ ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
+ reg);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+ goto err;
+ }
+
+err:
+ mutex_unlock(&opt->lock);
+
+ return ret;
+}
+
+static const struct iio_info opt3001_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &opt3001_attribute_group,
+ .read_raw = opt3001_read_raw,
+ .write_raw = opt3001_write_raw,
+ .read_event_value = opt3001_read_event_value,
+ .write_event_value = opt3001_write_event_value,
+ .read_event_config = opt3001_read_event_config,
+ .write_event_config = opt3001_write_event_config,
+};
+
+static int opt3001_read_id(struct opt3001 *opt)
+{
+ char manufacturer[2];
+ u16 device_id;
+ int ret;
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_MANUFACTURER_ID);
+ return ret;
+ }
+
+ manufacturer[0] = ret >> 8;
+ manufacturer[1] = ret & 0xff;
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_DEVICE_ID);
+ return ret;
+ }
+
+ device_id = ret;
+
+ dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0],
+ manufacturer[1], device_id);
+
+ return 0;
+}
+
+static int opt3001_configure(struct opt3001 *opt)
+{
+ int ret;
+ u16 reg;
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
+ }
+
+ reg = ret;
+
+ /* Enable automatic full-scale setting mode */
+ reg &= ~OPT3001_CONFIGURATION_RN_MASK;
+ reg |= OPT3001_CONFIGURATION_RN_AUTO;
+
+ /* Reflect status of the device's integration time setting */
+ if (reg & OPT3001_CONFIGURATION_CT)
+ opt->int_time = 800000;
+ else
+ opt->int_time = 100000;
+
+ /* Ensure device is in shutdown initially */
+ opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SHUTDOWN);
+
+ /* Configure for latched window-style comparison operation */
+ reg |= OPT3001_CONFIGURATION_L;
+ reg &= ~OPT3001_CONFIGURATION_POL;
+ reg &= ~OPT3001_CONFIGURATION_ME;
+ reg &= ~OPT3001_CONFIGURATION_FC_MASK;
+
+ ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
+ reg);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
+ }
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_LOW_LIMIT);
+ return ret;
+ }
+
+ opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
+ opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret);
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_HIGH_LIMIT);
+ return ret;
+ }
+
+ opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret);
+ opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret);
+
+ return 0;
+}
+
+static irqreturn_t opt3001_irq(int irq, void *_iio)
+{
+ struct iio_dev *iio = _iio;
+ struct opt3001 *opt = iio_priv(iio);
+ int ret;
+
+ if (!opt->ok_to_ignore_lock)
+ mutex_lock(&opt->lock);
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ goto out;
+ }
+
+ if ((ret & OPT3001_CONFIGURATION_M_MASK) ==
+ OPT3001_CONFIGURATION_M_CONTINUOUS) {
+ if (ret & OPT3001_CONFIGURATION_FH)
+ iio_push_event(iio,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ iio_get_time_ns());
+ if (ret & OPT3001_CONFIGURATION_FL)
+ iio_push_event(iio,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ iio_get_time_ns());
+ } else if (ret & OPT3001_CONFIGURATION_CRF) {
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_RESULT);
+ goto out;
+ }
+ opt->result = ret;
+ opt->result_ready = true;
+ wake_up(&opt->result_ready_queue);
+ }
+
+out:
+ if (!opt->ok_to_ignore_lock)
+ mutex_unlock(&opt->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int opt3001_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+
+ struct iio_dev *iio;
+ struct opt3001 *opt;
+ int irq = client->irq;
+ int ret;
+
+ iio = devm_iio_device_alloc(dev, sizeof(*opt));
+ if (!iio)
+ return -ENOMEM;
+
+ opt = iio_priv(iio);
+ opt->client = client;
+ opt->dev = dev;
+
+ mutex_init(&opt->lock);
+ init_waitqueue_head(&opt->result_ready_queue);
+ i2c_set_clientdata(client, iio);
+
+ ret = opt3001_read_id(opt);
+ if (ret)
+ return ret;
+
+ ret = opt3001_configure(opt);
+ if (ret)
+ return ret;
+
+ iio->name = client->name;
+ iio->channels = opt3001_channels;
+ iio->num_channels = ARRAY_SIZE(opt3001_channels);
+ iio->dev.parent = dev;
+ iio->modes = INDIO_DIRECT_MODE;
+ iio->info = &opt3001_info;
+
+ ret = devm_iio_device_register(dev, iio);
+ if (ret) {
+ dev_err(dev, "failed to register IIO device\n");
+ return ret;
+ }
+
+ ret = request_threaded_irq(irq, NULL, opt3001_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "opt3001", iio);
+ if (ret) {
+ dev_err(dev, "failed to request IRQ #%d\n", irq);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int opt3001_remove(struct i2c_client *client)
+{
+ struct iio_dev *iio = i2c_get_clientdata(client);
+ struct opt3001 *opt = iio_priv(iio);
+ int ret;
+ u16 reg;
+
+ free_irq(client->irq, iio);
+
+ ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to read register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
+ }
+
+ reg = ret;
+ opt3001_set_mode(opt, &reg, OPT3001_CONFIGURATION_M_SHUTDOWN);
+
+ ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION,
+ reg);
+ if (ret < 0) {
+ dev_err(opt->dev, "failed to write register %02x\n",
+ OPT3001_CONFIGURATION);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id opt3001_id[] = {
+ { "opt3001", 0 },
+ { } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(i2c, opt3001_id);
+
+static const struct of_device_id opt3001_of_match[] = {
+ { .compatible = "ti,opt3001" },
+ { }
+};
+
+static struct i2c_driver opt3001_driver = {
+ .probe = opt3001_probe,
+ .remove = opt3001_remove,
+ .id_table = opt3001_id,
+
+ .driver = {
+ .name = "opt3001",
+ .of_match_table = of_match_ptr(opt3001_of_match),
+ .owner = THIS_MODULE,
+ },
+};
+
+module_i2c_driver(opt3001_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>");
+MODULE_DESCRIPTION("Texas Instruments OPT3001 Light Sensor Driver");
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
new file mode 100644
index 000000000000..45f7bde02bbf
--- /dev/null
+++ b/drivers/iio/light/pa12203001.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Driver for TXC PA12203001 Proximity and Ambient Light Sensor.
+ *
+ * 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.
+ * To do: Interrupt support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#define PA12203001_DRIVER_NAME "pa12203001"
+
+#define PA12203001_REG_CFG0 0x00
+#define PA12203001_REG_CFG1 0x01
+#define PA12203001_REG_CFG2 0x02
+#define PA12203001_REG_CFG3 0x03
+
+#define PA12203001_REG_ADL 0x0b
+#define PA12203001_REG_PDH 0x0e
+
+#define PA12203001_REG_POFS 0x10
+#define PA12203001_REG_PSET 0x11
+
+#define PA12203001_ALS_EN_MASK BIT(0)
+#define PA12203001_PX_EN_MASK BIT(1)
+#define PA12203001_PX_NORMAL_MODE_MASK GENMASK(7, 6)
+#define PA12203001_AFSR_MASK GENMASK(5, 4)
+#define PA12203001_AFSR_SHIFT 4
+
+#define PA12203001_PSCAN 0x03
+
+/* als range 31000, ps, als disabled */
+#define PA12203001_REG_CFG0_DEFAULT 0x30
+
+/* led current: 100 mA */
+#define PA12203001_REG_CFG1_DEFAULT 0x20
+
+/* ps mode: normal, interrupts not active */
+#define PA12203001_REG_CFG2_DEFAULT 0xcc
+
+#define PA12203001_REG_CFG3_DEFAULT 0x00
+
+#define PA12203001_SLEEP_DELAY_MS 3000
+
+#define PA12203001_CHIP_ENABLE 0xff
+#define PA12203001_CHIP_DISABLE 0x00
+
+/* available scales: corresponding to [500, 4000, 7000, 31000] lux */
+static const int pa12203001_scales[] = { 7629, 61036, 106813, 473029};
+
+struct pa12203001_data {
+ struct i2c_client *client;
+
+ /* protect device states */
+ struct mutex lock;
+
+ bool als_enabled;
+ bool px_enabled;
+ bool als_needs_enable;
+ bool px_needs_enable;
+
+ struct regmap *map;
+};
+
+static const struct {
+ u8 reg;
+ u8 val;
+} regvals[] = {
+ {PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT},
+ {PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT},
+ {PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT},
+ {PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT},
+ {PA12203001_REG_PSET, PA12203001_PSCAN},
+};
+
+static IIO_CONST_ATTR(in_illuminance_scale_available,
+ "0.007629 0.061036 0.106813 0.473029");
+
+static struct attribute *pa12203001_attrs[] = {
+ &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group pa12203001_attr_group = {
+ .attrs = pa12203001_attrs,
+};
+
+static const struct iio_chan_spec pa12203001_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_PROXIMITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }
+};
+
+static const struct regmap_range pa12203001_volatile_regs_ranges[] = {
+ regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1),
+ regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH),
+};
+
+static const struct regmap_access_table pa12203001_volatile_regs = {
+ .yes_ranges = pa12203001_volatile_regs_ranges,
+ .n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges),
+};
+
+static const struct regmap_config pa12203001_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PA12203001_REG_PSET,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_table = &pa12203001_volatile_regs,
+};
+
+static inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable)
+{
+ int ret;
+
+ ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
+ PA12203001_ALS_EN_MASK, enable);
+ if (ret < 0)
+ return ret;
+
+ data->als_enabled = !!enable;
+
+ return 0;
+}
+
+static inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable)
+{
+ int ret;
+
+ ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
+ PA12203001_PX_EN_MASK, enable);
+ if (ret < 0)
+ return ret;
+
+ data->px_enabled = !!enable;
+
+ return 0;
+}
+
+static int pa12203001_set_power_state(struct pa12203001_data *data, bool on,
+ u8 mask)
+{
+#ifdef CONFIG_PM
+ int ret;
+
+ if (on && (mask & PA12203001_ALS_EN_MASK)) {
+ mutex_lock(&data->lock);
+ if (data->px_enabled) {
+ ret = pa12203001_als_enable(data,
+ PA12203001_ALS_EN_MASK);
+ if (ret < 0)
+ goto err;
+ } else {
+ data->als_needs_enable = true;
+ }
+ mutex_unlock(&data->lock);
+ }
+
+ if (on && (mask & PA12203001_PX_EN_MASK)) {
+ mutex_lock(&data->lock);
+ if (data->als_enabled) {
+ ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
+ if (ret < 0)
+ goto err;
+ } else {
+ data->px_needs_enable = true;
+ }
+ mutex_unlock(&data->lock);
+ }
+
+ 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;
+
+err:
+ mutex_unlock(&data->lock);
+ return ret;
+
+#endif
+ return 0;
+}
+
+static int pa12203001_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct pa12203001_data *data = iio_priv(indio_dev);
+ int ret;
+ u8 dev_mask;
+ unsigned int reg_byte;
+ __le16 reg_word;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ dev_mask = PA12203001_ALS_EN_MASK;
+ ret = pa12203001_set_power_state(data, true, dev_mask);
+ if (ret < 0)
+ return ret;
+ /*
+ * ALS ADC value is stored in registers
+ * PA12203001_REG_ADL and in PA12203001_REG_ADL + 1.
+ */
+ ret = regmap_bulk_read(data->map, PA12203001_REG_ADL,
+ &reg_word, 2);
+ if (ret < 0)
+ goto reg_err;
+
+ *val = le16_to_cpu(reg_word);
+ ret = pa12203001_set_power_state(data, false, dev_mask);
+ if (ret < 0)
+ return ret;
+ break;
+ case IIO_PROXIMITY:
+ dev_mask = PA12203001_PX_EN_MASK;
+ ret = pa12203001_set_power_state(data, true, dev_mask);
+ if (ret < 0)
+ return ret;
+ ret = regmap_read(data->map, PA12203001_REG_PDH,
+ &reg_byte);
+ if (ret < 0)
+ goto reg_err;
+
+ *val = reg_byte;
+ ret = pa12203001_set_power_state(data, false, dev_mask);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = regmap_read(data->map, PA12203001_REG_CFG0, &reg_byte);
+ if (ret < 0)
+ return ret;
+ *val = 0;
+ reg_byte = (reg_byte & PA12203001_AFSR_MASK);
+ *val2 = pa12203001_scales[reg_byte >> 4];
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+
+reg_err:
+ pa12203001_set_power_state(data, false, dev_mask);
+ return ret;
+}
+
+static int pa12203001_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct pa12203001_data *data = iio_priv(indio_dev);
+ int i, ret, new_val;
+ unsigned int reg_byte;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ ret = regmap_read(data->map, PA12203001_REG_CFG0, &reg_byte);
+ if (val != 0 || ret < 0)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) {
+ if (val2 == pa12203001_scales[i]) {
+ new_val = i << PA12203001_AFSR_SHIFT;
+ return regmap_update_bits(data->map,
+ PA12203001_REG_CFG0,
+ PA12203001_AFSR_MASK,
+ new_val);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info pa12203001_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = pa12203001_read_raw,
+ .write_raw = pa12203001_write_raw,
+ .attrs = &pa12203001_attr_group,
+};
+
+static int pa12203001_init(struct iio_dev *indio_dev)
+{
+ struct pa12203001_data *data = iio_priv(indio_dev);
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(regvals); i++) {
+ ret = regmap_write(data->map, regvals[i].reg, regvals[i].val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state)
+{
+ struct pa12203001_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+ ret = pa12203001_als_enable(data, state);
+ if (ret < 0)
+ goto out;
+
+ ret = pa12203001_px_enable(data, state);
+
+out:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int pa12203001_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pa12203001_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev,
+ sizeof(struct pa12203001_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config);
+ if (IS_ERR(data->map))
+ return PTR_ERR(data->map);
+
+ mutex_init(&data->lock);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->info = &pa12203001_info;
+ indio_dev->name = PA12203001_DRIVER_NAME;
+ indio_dev->channels = pa12203001_channels;
+ indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = pa12203001_init(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
+ if (ret < 0)
+ return ret;
+
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret < 0) {
+ pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
+ return ret;
+ }
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev,
+ PA12203001_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ return iio_device_register(indio_dev);
+}
+
+static int pa12203001_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
+}
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
+static int pa12203001_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+
+ return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int pa12203001_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+
+ return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int pa12203001_runtime_resume(struct device *dev)
+{
+ struct pa12203001_data *data;
+
+ data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+ mutex_lock(&data->lock);
+ if (data->als_needs_enable) {
+ pa12203001_als_enable(data, PA12203001_ALS_EN_MASK);
+ data->als_needs_enable = false;
+ }
+ if (data->px_needs_enable) {
+ pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
+ data->px_needs_enable = false;
+ }
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops pa12203001_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume)
+ SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id pa12203001_acpi_match[] = {
+ { "TXCPA122", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
+
+static const struct i2c_device_id pa12203001_id[] = {
+ {"txcpa122", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pa12203001_id);
+
+static struct i2c_driver pa12203001_driver = {
+ .driver = {
+ .name = PA12203001_DRIVER_NAME,
+ .pm = &pa12203001_pm_ops,
+ .acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
+ },
+ .probe = pa12203001_probe,
+ .remove = pa12203001_remove,
+ .id_table = pa12203001_id,
+
+};
+module_i2c_driver(pa12203001_driver);
+
+MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
+MODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 11a027adc204..f101bb5bddc7 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -676,6 +676,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = {
{"STK3311", 0},
{}
};
+MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
static const struct acpi_device_id stk3310_acpi_id[] = {
{"STK3310", 0},
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index 7da4ce9409e8..e330205f8194 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -85,6 +85,7 @@
#define BMC150_MAGN_REG_HIGH_THRESH 0x50
#define BMC150_MAGN_REG_REP_XY 0x51
#define BMC150_MAGN_REG_REP_Z 0x52
+#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0)
#define BMC150_MAGN_REG_TRIM_START 0x5D
#define BMC150_MAGN_REG_TRIM_END 0x71
@@ -559,7 +560,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
}
ret = regmap_update_bits(data->regmap,
BMC150_MAGN_REG_REP_XY,
- 0xFF,
+ BMC150_MAGN_REG_REP_DATAMASK,
BMC150_MAGN_REPXY_TO_REGVAL
(val));
mutex_unlock(&data->mutex);
@@ -575,7 +576,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev,
}
ret = regmap_update_bits(data->regmap,
BMC150_MAGN_REG_REP_Z,
- 0xFF,
+ BMC150_MAGN_REG_REP_DATAMASK,
BMC150_MAGN_REPZ_TO_REGVAL
(val));
mutex_unlock(&data->mutex);
@@ -651,7 +652,9 @@ static const struct iio_info bmc150_magn_info = {
.driver_module = THIS_MODULE,
};
-static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0};
+static const unsigned long bmc150_magn_scan_masks[] = {
+ BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+ 0};
static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
{
@@ -662,7 +665,6 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
mutex_lock(&data->mutex);
ret = bmc150_magn_read_xyz(data, data->buffer);
- mutex_unlock(&data->mutex);
if (ret < 0)
goto err;
@@ -670,6 +672,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p)
pf->timestamp);
err:
+ mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -781,29 +784,23 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig,
if (state == data->dready_trigger_on)
goto err_unlock;
- ret = bmc150_magn_set_power_state(data, state);
- if (ret < 0)
- goto err_unlock;
-
ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY,
BMC150_MAGN_MASK_DRDY_EN,
state << BMC150_MAGN_SHIFT_DRDY_EN);
if (ret < 0)
- goto err_poweroff;
+ goto err_unlock;
data->dready_trigger_on = state;
if (state) {
ret = bmc150_magn_reset_intr(data);
if (ret < 0)
- goto err_poweroff;
+ goto err_unlock;
}
mutex_unlock(&data->mutex);
return 0;
-err_poweroff:
- bmc150_magn_set_power_state(data, false);
err_unlock:
mutex_unlock(&data->mutex);
return ret;
@@ -1041,6 +1038,9 @@ static int bmc150_magn_runtime_suspend(struct device *dev)
return 0;
}
+/*
+ * Should be called with data->mutex held.
+ */
static int bmc150_magn_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c
index 706ebfd6297f..176e14a61558 100644
--- a/drivers/iio/magnetometer/mmc35240.c
+++ b/drivers/iio/magnetometer/mmc35240.c
@@ -316,31 +316,31 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])
static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index,
__le16 buf[], int *val)
{
- int raw_x, raw_y, raw_z;
- int sens_x, sens_y, sens_z;
+ int raw[3];
+ int sens[3];
int nfo;
- raw_x = le16_to_cpu(buf[AXIS_X]);
- raw_y = le16_to_cpu(buf[AXIS_Y]);
- raw_z = le16_to_cpu(buf[AXIS_Z]);
+ raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]);
+ raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]);
+ raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]);
- sens_x = mmc35240_props_table[data->res].sens[AXIS_X];
- sens_y = mmc35240_props_table[data->res].sens[AXIS_Y];
- sens_z = mmc35240_props_table[data->res].sens[AXIS_Z];
+ sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X];
+ sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y];
+ sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z];
nfo = mmc35240_props_table[data->res].nfo;
switch (index) {
case AXIS_X:
- *val = (raw_x - nfo) * 1000 / sens_x;
+ *val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X];
break;
case AXIS_Y:
- *val = (raw_y - nfo) * 1000 / sens_y -
- (raw_z - nfo) * 1000 / sens_z;
+ *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] -
+ (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];
break;
case AXIS_Z:
- *val = (raw_y - nfo) * 1000 / sens_y +
- (raw_z - nfo) * 1000 / sens_z;
+ *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] +
+ (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];
break;
default:
return -EINVAL;
@@ -559,6 +559,12 @@ static const struct dev_pm_ops mmc35240_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume)
};
+static const struct of_device_id mmc35240_of_match[] = {
+ { .compatible = "memsic,mmc35240", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mmc35240_of_match);
+
static const struct acpi_device_id mmc35240_acpi_match[] = {
{"MMC35240", 0},
{ },
@@ -574,6 +580,7 @@ MODULE_DEVICE_TABLE(i2c, mmc35240_id);
static struct i2c_driver mmc35240_driver = {
.driver = {
.name = MMC35240_DRV_NAME,
+ .of_match_table = mmc35240_of_match,
.pm = &mmc35240_pm_ops,
.acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
},
diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h
index 287691ca56c1..06a4d9c35581 100644
--- a/drivers/iio/magnetometer/st_magn.h
+++ b/drivers/iio/magnetometer/st_magn.h
@@ -18,6 +18,7 @@
#define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn"
#define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn"
#define LIS3MDL_MAGN_DEV_NAME "lis3mdl"
+#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn"
int st_magn_common_probe(struct iio_dev *indio_dev);
void st_magn_common_remove(struct iio_dev *indio_dev);
@@ -25,6 +26,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev);
#ifdef CONFIG_IIO_BUFFER
int st_magn_allocate_ring(struct iio_dev *indio_dev);
void st_magn_deallocate_ring(struct iio_dev *indio_dev);
+int st_magn_trig_set_state(struct iio_trigger *trig, bool state);
+#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq)
{
diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c
index bf427dc0d226..ecd3bd0a9769 100644
--- a/drivers/iio/magnetometer/st_magn_buffer.c
+++ b/drivers/iio/magnetometer/st_magn_buffer.c
@@ -23,6 +23,13 @@
#include <linux/iio/common/st_sensors.h>
#include "st_magn.h"
+int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+
+ return st_sensors_set_dataready_irq(indio_dev, state);
+}
+
static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
{
return st_sensors_set_enable(indio_dev, true);
diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c
index b4bcfb790f49..f8dc4b85d70c 100644
--- a/drivers/iio/magnetometer/st_magn_core.c
+++ b/drivers/iio/magnetometer/st_magn_core.c
@@ -43,6 +43,7 @@
#define ST_MAGN_FS_AVL_8000MG 8000
#define ST_MAGN_FS_AVL_8100MG 8100
#define ST_MAGN_FS_AVL_12000MG 12000
+#define ST_MAGN_FS_AVL_15000MG 15000
#define ST_MAGN_FS_AVL_16000MG 16000
/* CUSTOM VALUES FOR SENSOR 0 */
@@ -157,6 +158,29 @@
#define ST_MAGN_2_OUT_Y_L_ADDR 0x2a
#define ST_MAGN_2_OUT_Z_L_ADDR 0x2c
+/* CUSTOM VALUES FOR SENSOR 3 */
+#define ST_MAGN_3_WAI_ADDR 0x4f
+#define ST_MAGN_3_WAI_EXP 0x40
+#define ST_MAGN_3_ODR_ADDR 0x60
+#define ST_MAGN_3_ODR_MASK 0x0c
+#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00
+#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01
+#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02
+#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03
+#define ST_MAGN_3_PW_ADDR 0x60
+#define ST_MAGN_3_PW_MASK 0x03
+#define ST_MAGN_3_PW_ON 0x00
+#define ST_MAGN_3_PW_OFF 0x03
+#define ST_MAGN_3_BDU_ADDR 0x62
+#define ST_MAGN_3_BDU_MASK 0x10
+#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62
+#define ST_MAGN_3_DRDY_INT_MASK 0x01
+#define ST_MAGN_3_FS_AVL_15000_GAIN 1500
+#define ST_MAGN_3_MULTIREAD_BIT false
+#define ST_MAGN_3_OUT_X_L_ADDR 0x68
+#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a
+#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c
+
static const struct iio_chan_spec st_magn_16bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
@@ -189,9 +213,26 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3)
};
+static const struct iio_chan_spec st_magn_3_16bit_channels[] = {
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16,
+ ST_MAGN_3_OUT_X_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16,
+ ST_MAGN_3_OUT_Y_L_ADDR),
+ ST_SENSORS_LSM_CHANNELS(IIO_MAGN,
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16,
+ ST_MAGN_3_OUT_Z_L_ADDR),
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
static const struct st_sensor_settings st_magn_sensors_settings[] = {
{
.wai = 0, /* This sensor has no valid WhoAmI report 0 */
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM303DLH_MAGN_DEV_NAME,
},
@@ -268,6 +309,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
},
{
.wai = ST_MAGN_1_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LSM303DLHC_MAGN_DEV_NAME,
[1] = LSM303DLM_MAGN_DEV_NAME,
@@ -346,6 +388,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
},
{
.wai = ST_MAGN_2_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3MDL_MAGN_DEV_NAME,
},
@@ -399,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.multi_read_bit = ST_MAGN_2_MULTIREAD_BIT,
.bootime = 2,
},
+ {
+ .wai = ST_MAGN_3_WAI_EXP,
+ .wai_addr = ST_MAGN_3_WAI_ADDR,
+ .sensors_supported = {
+ [0] = LSM303AGR_MAGN_DEV_NAME,
+ },
+ .ch = (struct iio_chan_spec *)st_magn_3_16bit_channels,
+ .odr = {
+ .addr = ST_MAGN_3_ODR_ADDR,
+ .mask = ST_MAGN_3_ODR_MASK,
+ .odr_avl = {
+ { 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, },
+ { 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, },
+ { 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, },
+ { 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, },
+ },
+ },
+ .pw = {
+ .addr = ST_MAGN_3_PW_ADDR,
+ .mask = ST_MAGN_3_PW_MASK,
+ .value_on = ST_MAGN_3_PW_ON,
+ .value_off = ST_MAGN_3_PW_OFF,
+ },
+ .fs = {
+ .fs_avl = {
+ [0] = {
+ .num = ST_MAGN_FS_AVL_15000MG,
+ .gain = ST_MAGN_3_FS_AVL_15000_GAIN,
+ },
+ },
+ },
+ .bdu = {
+ .addr = ST_MAGN_3_BDU_ADDR,
+ .mask = ST_MAGN_3_BDU_MASK,
+ },
+ .drdy_irq = {
+ .addr = ST_MAGN_3_DRDY_IRQ_ADDR,
+ .mask_int1 = ST_MAGN_3_DRDY_INT_MASK,
+ },
+ .multi_read_bit = ST_MAGN_3_MULTIREAD_BIT,
+ .bootime = 2,
+ },
};
static int st_magn_read_raw(struct iio_dev *indio_dev,
@@ -477,6 +562,16 @@ static const struct iio_info magn_info = {
.write_raw = &st_magn_write_raw,
};
+#ifdef CONFIG_IIO_TRIGGER
+static const struct iio_trigger_ops st_magn_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = ST_MAGN_TRIGGER_SET_STATE,
+};
+#define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops)
+#else
+#define ST_MAGN_TRIGGER_OPS NULL
+#endif
+
int st_magn_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *mdata = iio_priv(indio_dev);
@@ -513,7 +608,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
return err;
if (irq > 0) {
- err = st_sensors_allocate_trigger(indio_dev, NULL);
+ err = st_sensors_allocate_trigger(indio_dev,
+ ST_MAGN_TRIGGER_OPS);
if (err < 0)
goto st_magn_probe_trigger_error;
}
diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c
index 28aa80731cea..8aa37af306ed 100644
--- a/drivers/iio/magnetometer/st_magn_i2c.c
+++ b/drivers/iio/magnetometer/st_magn_i2c.c
@@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = {
.compatible = "st,lis3mdl-magn",
.data = LIS3MDL_MAGN_DEV_NAME,
},
+ {
+ .compatible = "st,lsm303agr-magn",
+ .data = LSM303AGR_MAGN_DEV_NAME,
+ },
{},
};
MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
{ LSM303DLHC_MAGN_DEV_NAME },
{ LSM303DLM_MAGN_DEV_NAME },
{ LIS3MDL_MAGN_DEV_NAME },
+ { LSM303AGR_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 7adacf160146..0abca2c6afa6 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = {
{ LSM303DLHC_MAGN_DEV_NAME },
{ LSM303DLM_MAGN_DEV_NAME },
{ LIS3MDL_MAGN_DEV_NAME },
+ { LSM303AGR_MAGN_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_magn_id_table);
diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c
index e881fa6291e9..eb41d2b92c24 100644
--- a/drivers/iio/pressure/st_pressure_core.c
+++ b/drivers/iio/pressure/st_pressure_core.c
@@ -178,6 +178,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = {
static const struct st_sensor_settings st_press_sensors_settings[] = {
{
.wai = ST_PRESS_LPS331AP_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LPS331AP_PRESS_DEV_NAME,
},
@@ -225,6 +226,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
},
{
.wai = ST_PRESS_LPS001WP_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LPS001WP_PRESS_DEV_NAME,
},
@@ -260,6 +262,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
},
{
.wai = ST_PRESS_LPS25H_WAI_EXP,
+ .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LPS25H_PRESS_DEV_NAME,
},
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index e4ec7af4c1bf..5d033a5af615 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -65,6 +65,13 @@
#define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */
+/* Magic constants */
+#define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */
+#define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */
+#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
+#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
+#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
+
struct mlx90614_data {
struct i2c_client *client;
struct mutex lock; /* for EEPROM access only */
@@ -204,11 +211,11 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
- *val = -13657;
- *val2 = 500000;
+ *val = MLX90614_CONST_OFFSET_DEC;
+ *val2 = MLX90614_CONST_OFFSET_REM;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
- *val = 20;
+ *val = MLX90614_CONST_SCALE;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
mlx90614_power_get(data, false);
@@ -221,12 +228,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
- if (ret == 65535) {
+ if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) {
*val = 1;
*val2 = 0;
} else {
*val = 0;
- *val2 = ret * 15259; /* 1/65535 ~ 0.000015259 */
+ *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION;
}
return IIO_VAL_INT_PLUS_NANO;
default:
@@ -245,7 +252,8 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */
if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0))
return -EINVAL;
- val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */
+ val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX +
+ val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION;
mlx90614_power_get(data, false);
mutex_lock(&data->lock);
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index d7c5223f1c3e..3f7715c9968b 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -1,5 +1,5 @@
/*
- * Freescale i.MX28 LRADC driver
+ * Freescale MXS LRADC driver
*
* Copyright (c) 2012 DENX Software Engineering, GmbH.
* Marek Vasut <marex@denx.de>
@@ -15,34 +15,30 @@
* GNU General Public License for more details.
*/
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/device.h>
#include <linux/err.h>
+#include <linux/input.h>
#include <linux/interrupt.h>
-#include <linux/device.h>
+#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/io.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
+#include <linux/slab.h>
#include <linux/stmp_device.h>
-#include <linux/bitops.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/clk.h>
+#include <linux/sysfs.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/sysfs.h>
#define DRIVER_NAME "mxs-lradc"
@@ -65,14 +61,14 @@
* Once the pen touches the touchscreen, the touchscreen switches from
* IRQ-driven mode to polling mode to prevent interrupt storm. The polling
* is realized by worker thread, which is called every 20 or so milliseconds.
- * This gives the touchscreen enough fluence and does not strain the system
+ * This gives the touchscreen enough fluency and does not strain the system
* too much.
*/
#define LRADC_TS_SAMPLE_DELAY_MS 5
/*
* The LRADC reads the following amount of samples from each touchscreen
- * channel and the driver then computes avarage of these.
+ * channel and the driver then computes average of these.
*/
#define LRADC_TS_SAMPLE_AMOUNT 4
@@ -238,7 +234,7 @@ struct mxs_lradc {
* CH5 -- Touch screen YNLR
* CH6 -- Touch screen WIPER (5-wire only)
*
- * The bitfields below represents which parts of the LRADC block are
+ * The bit fields below represents which parts of the LRADC block are
* switched into special mode of operation. These channels can not
* be sampled as regular LRADC channels. The driver will refuse any
* attempt to sample these channels.
@@ -252,7 +248,7 @@ struct mxs_lradc {
struct input_dev *ts_input;
enum mxs_lradc_id soc;
- enum lradc_ts_plate cur_plate; /* statemachine */
+ enum lradc_ts_plate cur_plate; /* state machine */
bool ts_valid;
unsigned ts_x_pos;
unsigned ts_y_pos;
@@ -812,7 +808,7 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val)
int ret;
/*
- * See if there is no buffered operation in progess. If there is, simply
+ * See if there is no buffered operation in progress. If there is, simply
* bail out. This can be improved to support both buffered and raw IO at
* the same time, yet the code becomes horribly complicated. Therefore I
* applied KISS principle here.
@@ -1369,7 +1365,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
* Driver initialization
*/
-#define MXS_ADC_CHAN(idx, chan_type) { \
+#define MXS_ADC_CHAN(idx, chan_type, name) { \
.type = (chan_type), \
.indexed = 1, \
.scan_index = (idx), \
@@ -1382,17 +1378,18 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.realbits = LRADC_RESOLUTION, \
.storagebits = 32, \
}, \
+ .datasheet_name = (name), \
}
-static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
- MXS_ADC_CHAN(0, IIO_VOLTAGE),
- MXS_ADC_CHAN(1, IIO_VOLTAGE),
- MXS_ADC_CHAN(2, IIO_VOLTAGE),
- MXS_ADC_CHAN(3, IIO_VOLTAGE),
- MXS_ADC_CHAN(4, IIO_VOLTAGE),
- MXS_ADC_CHAN(5, IIO_VOLTAGE),
- MXS_ADC_CHAN(6, IIO_VOLTAGE),
- MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */
+static const struct iio_chan_spec mx23_lradc_chan_spec[] = {
+ MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
+ MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
+ MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
+ MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
+ MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
+ MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
+ MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"),
+ MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
/* Combined Temperature sensors */
{
.type = IIO_TEMP,
@@ -1403,6 +1400,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
BIT(IIO_CHAN_INFO_SCALE),
.channel = 8,
.scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
+ .datasheet_name = "TEMP_DIE",
},
/* Hidden channel to keep indexes */
{
@@ -1411,12 +1409,48 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
.scan_index = -1,
.channel = 9,
},
- MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */
- MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */
- MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */
- MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */
- MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */
- MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */
+ MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL),
+ MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL),
+ MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"),
+ MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"),
+ MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
+ MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
+};
+
+static const struct iio_chan_spec mx28_lradc_chan_spec[] = {
+ MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"),
+ MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"),
+ MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"),
+ MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"),
+ MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"),
+ MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"),
+ MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"),
+ MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"),
+ /* Combined Temperature sensors */
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .scan_index = 8,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .channel = 8,
+ .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,},
+ .datasheet_name = "TEMP_DIE",
+ },
+ /* Hidden channel to keep indexes */
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .scan_index = -1,
+ .channel = 9,
+ },
+ MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"),
+ MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"),
+ MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"),
+ MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"),
+ MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"),
+ MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"),
};
static int mxs_lradc_hw_init(struct mxs_lradc *lradc)
@@ -1612,10 +1646,16 @@ static int mxs_lradc_probe(struct platform_device *pdev)
iio->dev.parent = &pdev->dev;
iio->info = &mxs_lradc_iio_info;
iio->modes = INDIO_DIRECT_MODE;
- iio->channels = mxs_lradc_chan_spec;
- iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec);
iio->masklength = LRADC_MAX_TOTAL_CHANS;
+ if (lradc->soc == IMX23_LRADC) {
+ iio->channels = mx23_lradc_chan_spec;
+ iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec);
+ } else {
+ iio->channels = mx28_lradc_chan_spec;
+ iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec);
+ }
+
ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
&mxs_lradc_trigger_handler,
&mxs_lradc_buffer_ops);
@@ -1707,6 +1747,6 @@ static struct platform_driver mxs_lradc_driver = {
module_platform_driver(mxs_lradc_driver);
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
-MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver");
+MODULE_DESCRIPTION("Freescale MXS LRADC driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index 2c476acb87d9..3c17cd7fdf06 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -166,6 +166,7 @@ struct st_sensor_transfer_function {
/**
* struct st_sensor_settings - ST specific sensor settings
* @wai: Contents of WhoAmI register.
+ * @wai_addr: The address of WhoAmI register.
* @sensors_supported: List of supported sensors by struct itself.
* @ch: IIO channels for the sensor.
* @odr: Output data rate register and ODR list available.
@@ -179,6 +180,7 @@ struct st_sensor_transfer_function {
*/
struct st_sensor_settings {
u8 wai;
+ u8 wai_addr;
char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME];
struct iio_chan_spec *ch;
int num_ch;
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 26fb8f6342bb..fad58671c49e 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -100,7 +100,7 @@ void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff);
/**
* iio_channel_cb_get_channels() - get access to the underlying channels.
- * @cb_buff: The callback buffer from whom we want the channel
+ * @cb_buffer: The callback buffer from whom we want the channel
* information.
*
* This function allows one to obtain information about the channels.
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index f79148261d16..7bb7f673cb3f 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -645,6 +645,15 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
#define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL)
/**
+ * IIO_RAD_TO_DEGREE() - Convert rad to degree
+ * @rad: A value in rad
+ *
+ * Returns the given value converted from rad to degree
+ */
+#define IIO_RAD_TO_DEGREE(rad) \
+ (((rad) * 18000000ULL + 314159ULL / 2) / 314159ULL)
+
+/**
* IIO_G_TO_M_S_2() - Convert g to meter / second**2
* @g: A value in g
*
@@ -652,4 +661,12 @@ int iio_str_to_fixpoint(const char *str, int fract_mult, int *integer,
*/
#define IIO_G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL)
+/**
+ * IIO_M_S_2_TO_G() - Convert meter / second**2 to g
+ * @ms2: A value in meter / second**2
+ *
+ * Returns the given value converted from meter / second**2 to g
+ */
+#define IIO_M_S_2_TO_G(ms2) (((ms2) * 100000ULL + 980665ULL / 2) / 980665ULL)
+
#endif /* _INDUSTRIAL_IO_H_ */
diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
index 8a1d18640ab9..9cd8f747212f 100644
--- a/include/linux/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
@@ -18,7 +18,8 @@ struct iio_chan_spec;
* struct iio_dev_attr - iio specific device attribute
* @dev_attr: underlying device attribute
* @address: associated register address
- * @l: list head for maintaining list of dynamically created attrs.
+ * @l: list head for maintaining list of dynamically created attrs
+ * @c: specification for the underlying channel
*/
struct iio_dev_attr {
struct device_attribute dev_attr;
diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h
index fa76c79a52a1..1c9e028e0d4a 100644
--- a/include/linux/iio/trigger.h
+++ b/include/linux/iio/trigger.h
@@ -18,6 +18,9 @@ struct iio_subirq {
bool enabled;
};
+struct iio_dev;
+struct iio_trigger;
+
/**
* struct iio_trigger_ops - operations structure for an iio_trigger.
* @owner: used to monitor usage count of the trigger.
diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c
index 0e737238ca74..9f7b85bf6ada 100644
--- a/tools/iio/generic_buffer.c
+++ b/tools/iio/generic_buffer.c
@@ -193,15 +193,15 @@ void process_scan(char *data,
void print_usage(void)
{
- printf("Usage: generic_buffer [options]...\n"
- "Capture, convert and output data from IIO device buffer\n"
- " -c <n> Do n conversions\n"
- " -e Disable wait for event (new data)\n"
- " -g Use trigger-less mode\n"
- " -l <n> Set buffer length to n samples\n"
- " -n <name> Set device name (mandatory)\n"
- " -t <name> Set trigger name\n"
- " -w <n> Set delay between reads in us (event-less mode)\n");
+ fprintf(stderr, "Usage: generic_buffer [options]...\n"
+ "Capture, convert and output data from IIO device buffer\n"
+ " -c <n> Do n conversions\n"
+ " -e Disable wait for event (new data)\n"
+ " -g Use trigger-less mode\n"
+ " -l <n> Set buffer length to n samples\n"
+ " -n <name> Set device name (mandatory)\n"
+ " -t <name> Set trigger name\n"
+ " -w <n> Set delay between reads in us (event-less mode)\n");
}
int main(int argc, char **argv)
@@ -270,8 +270,8 @@ int main(int argc, char **argv)
}
}
- if (device_name == NULL) {
- printf("Device name not set\n");
+ if (!device_name) {
+ fprintf(stderr, "Device name not set\n");
print_usage();
return -1;
}
@@ -279,7 +279,7 @@ int main(int argc, char **argv)
/* Find the device requested */
dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num < 0) {
- printf("Failed to find the %s\n", device_name);
+ fprintf(stderr, "Failed to find the %s\n", device_name);
return dev_num;
}
@@ -290,7 +290,7 @@ int main(int argc, char **argv)
return -ENOMEM;
if (!notrigger) {
- if (trigger_name == NULL) {
+ if (!trigger_name) {
/*
* Build the trigger name. If it is device associated
* its name is <device_name>_dev[n] where n matches
@@ -307,7 +307,8 @@ int main(int argc, char **argv)
/* Verify the trigger exists */
trig_num = find_type_by_name(trigger_name, "trigger");
if (trig_num < 0) {
- printf("Failed to find the trigger %s\n", trigger_name);
+ fprintf(stderr, "Failed to find the trigger %s\n",
+ trigger_name);
ret = trig_num;
goto error_free_triggername;
}
@@ -323,8 +324,8 @@ int main(int argc, char **argv)
*/
ret = build_channel_array(dev_dir_name, &channels, &num_channels);
if (ret) {
- printf("Problem reading scan element information\n");
- printf("diag %s\n", dev_dir_name);
+ fprintf(stderr, "Problem reading scan element information\n"
+ "diag %s\n", dev_dir_name);
goto error_free_triggername;
}
@@ -350,7 +351,8 @@ int main(int argc, char **argv)
dev_dir_name,
trigger_name);
if (ret < 0) {
- printf("Failed to write current_trigger file\n");
+ fprintf(stderr,
+ "Failed to write current_trigger file\n");
goto error_free_buf_dir_name;
}
}
@@ -362,8 +364,11 @@ int main(int argc, char **argv)
/* Enable the buffer */
ret = write_sysfs_int("enable", buf_dir_name, 1);
- if (ret < 0)
+ if (ret < 0) {
+ fprintf(stderr,
+ "Failed to enable buffer: %s\n", strerror(-ret));
goto error_free_buf_dir_name;
+ }
scan_size = size_from_channelarray(channels, num_channels);
data = malloc(scan_size * buf_len);
@@ -382,7 +387,7 @@ int main(int argc, char **argv)
fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /* TODO: If it isn't there make the node */
ret = -errno;
- printf("Failed to open %s\n", buffer_access);
+ fprintf(stderr, "Failed to open %s\n", buffer_access);
goto error_free_buffer_access;
}
@@ -410,7 +415,7 @@ int main(int argc, char **argv)
read_size = read(fp, data, toread * scan_size);
if (read_size < 0) {
if (errno == EAGAIN) {
- printf("nothing available\n");
+ fprintf(stderr, "nothing available\n");
continue;
} else {
break;
@@ -431,7 +436,8 @@ int main(int argc, char **argv)
ret = write_sysfs_string("trigger/current_trigger",
dev_dir_name, "NULL");
if (ret < 0)
- printf("Failed to write to %s\n", dev_dir_name);
+ fprintf(stderr, "Failed to write to %s\n",
+ dev_dir_name);
error_close_buffer_access:
if (close(fp) == -1)
diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c
index 703f4cb0e8e9..cd3fd41b481d 100644
--- a/tools/iio/iio_event_monitor.c
+++ b/tools/iio/iio_event_monitor.c
@@ -215,8 +215,8 @@ static void print_event(struct iio_event_data *event)
bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
if (!event_is_known(event)) {
- printf("Unknown event: time: %lld, id: %llx\n",
- event->timestamp, event->id);
+ fprintf(stderr, "Unknown event: time: %lld, id: %llx\n",
+ event->timestamp, event->id);
return;
}
@@ -251,7 +251,7 @@ int main(int argc, char **argv)
int fd, event_fd;
if (argc <= 1) {
- printf("Usage: %s <device_name>\n", argv[0]);
+ fprintf(stderr, "Usage: %s <device_name>\n", argv[0]);
return -1;
}
@@ -262,9 +262,8 @@ int main(int argc, char **argv)
printf("Found IIO device with name %s with device number %d\n",
device_name, dev_num);
ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
- if (ret < 0) {
+ if (ret < 0)
return -ENOMEM;
- }
} else {
/*
* If we can't find an IIO device by name assume device_name is
@@ -278,14 +277,14 @@ int main(int argc, char **argv)
fd = open(chrdev_name, 0);
if (fd == -1) {
ret = -errno;
- fprintf(stdout, "Failed to open %s\n", chrdev_name);
+ fprintf(stderr, "Failed to open %s\n", chrdev_name);
goto error_free_chrdev_name;
}
ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
if (ret == -1 || event_fd == -1) {
ret = -errno;
- fprintf(stdout, "Failed to retrieve event fd\n");
+ fprintf(stderr, "Failed to retrieve event fd\n");
if (close(fd) == -1)
perror("Failed to close character device file");
@@ -301,7 +300,7 @@ int main(int argc, char **argv)
ret = read(event_fd, &event, sizeof(event));
if (ret == -1) {
if (errno == EAGAIN) {
- printf("nothing available\n");
+ fprintf(stderr, "nothing available\n");
continue;
} else {
ret = -errno;
@@ -311,7 +310,7 @@ int main(int argc, char **argv)
}
if (ret != sizeof(event)) {
- printf("Reading event failed!\n");
+ fprintf(stderr, "Reading event failed!\n");
ret = -EIO;
break;
}
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c
index 8fb3214c70f2..5eb6793f3972 100644
--- a/tools/iio/iio_utils.c
+++ b/tools/iio/iio_utils.c
@@ -6,9 +6,6 @@
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
-#ifndef _IIO_UTILS_H
-#define _IIO_UTILS_H
-
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -39,7 +36,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name)
char *working, *prefix = "";
int i, ret;
- for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(iio_direction); i++)
if (!strncmp(full_name, iio_direction[i],
strlen(iio_direction[i]))) {
prefix = iio_direction[i];
@@ -117,13 +114,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
}
dp = opendir(scan_el_dir);
- if (dp == NULL) {
+ if (!dp) {
ret = -errno;
goto error_free_builtname_generic;
}
ret = -ENOENT;
- while (ent = readdir(dp), ent != NULL)
+ while (ent = readdir(dp), ent)
/*
* Do we allow devices to override a generic name with
* a specific one?
@@ -138,9 +135,10 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
}
sysfsfp = fopen(filename, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
- printf("failed to open %s\n", filename);
+ fprintf(stderr, "failed to open %s\n",
+ filename);
goto error_free_filename;
}
@@ -152,11 +150,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
&padint, shift);
if (ret < 0) {
ret = -errno;
- printf("failed to pass scan type description\n");
+ fprintf(stderr,
+ "failed to pass scan type description\n");
goto error_close_sysfsfp;
} else if (ret != 5) {
ret = -EIO;
- printf("scan type description didn't match\n");
+ fprintf(stderr,
+ "scan type description didn't match\n");
goto error_close_sysfsfp;
}
@@ -165,12 +165,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
if (*bits_used == 64)
*mask = ~0;
else
- *mask = (1 << *bits_used) - 1;
+ *mask = (1ULL << *bits_used) - 1;
*is_signed = (signchar == 's');
if (fclose(sysfsfp)) {
ret = -errno;
- printf("Failed to close %s\n", filename);
+ fprintf(stderr, "Failed to close %s\n",
+ filename);
goto error_free_filename;
}
@@ -235,13 +236,13 @@ int iioutils_get_param_float(float *output, const char *param_name,
}
dp = opendir(device_dir);
- if (dp == NULL) {
+ if (!dp) {
ret = -errno;
goto error_free_builtname_generic;
}
ret = -ENOENT;
- while (ent = readdir(dp), ent != NULL)
+ while (ent = readdir(dp), ent)
if ((strcmp(builtname, ent->d_name) == 0) ||
(strcmp(builtname_generic, ent->d_name) == 0)) {
ret = asprintf(&filename,
@@ -285,17 +286,17 @@ error_free_builtname:
* @cnt: the amount of array elements
**/
-void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt)
+void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt)
{
struct iio_channel_info temp;
int x, y;
for (x = 0; x < cnt; x++)
for (y = 0; y < (cnt - 1); y++)
- if ((*ci_array)[y].index > (*ci_array)[y + 1].index) {
- temp = (*ci_array)[y + 1];
- (*ci_array)[y + 1] = (*ci_array)[y];
- (*ci_array)[y] = temp;
+ if (ci_array[y].index > ci_array[y + 1].index) {
+ temp = ci_array[y + 1];
+ ci_array[y + 1] = ci_array[y];
+ ci_array[y] = temp;
}
}
@@ -325,12 +326,12 @@ int build_channel_array(const char *device_dir,
return -ENOMEM;
dp = opendir(scan_el_dir);
- if (dp == NULL) {
+ if (!dp) {
ret = -errno;
goto error_free_name;
}
- while (ent = readdir(dp), ent != NULL)
+ while (ent = readdir(dp), ent)
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
"_en") == 0) {
ret = asprintf(&filename,
@@ -341,7 +342,7 @@ int build_channel_array(const char *device_dir,
}
sysfsfp = fopen(filename, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
free(filename);
goto error_close_dir;
@@ -369,13 +370,13 @@ int build_channel_array(const char *device_dir,
}
*ci_array = malloc(sizeof(**ci_array) * (*counter));
- if (*ci_array == NULL) {
+ if (!*ci_array) {
ret = -ENOMEM;
goto error_close_dir;
}
seekdir(dp, 0);
- while (ent = readdir(dp), ent != NULL) {
+ while (ent = readdir(dp), ent) {
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
"_en") == 0) {
int current_enabled = 0;
@@ -391,7 +392,7 @@ int build_channel_array(const char *device_dir,
}
sysfsfp = fopen(filename, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
free(filename);
count--;
@@ -424,7 +425,7 @@ int build_channel_array(const char *device_dir,
current->name = strndup(ent->d_name,
strlen(ent->d_name) -
strlen("_en"));
- if (current->name == NULL) {
+ if (!current->name) {
free(filename);
ret = -ENOMEM;
count--;
@@ -452,9 +453,10 @@ int build_channel_array(const char *device_dir,
}
sysfsfp = fopen(filename, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
- printf("failed to open %s\n", filename);
+ fprintf(stderr, "failed to open %s\n",
+ filename);
free(filename);
goto error_cleanup_array;
}
@@ -482,7 +484,7 @@ int build_channel_array(const char *device_dir,
device_dir,
current->name,
current->generic_name);
- if (ret < 0)
+ if ((ret < 0) && (ret != -ENOENT))
goto error_cleanup_array;
ret = iioutils_get_param_float(&current->offset,
@@ -490,7 +492,7 @@ int build_channel_array(const char *device_dir,
device_dir,
current->name,
current->generic_name);
- if (ret < 0)
+ if ((ret < 0) && (ret != -ENOENT))
goto error_cleanup_array;
ret = iioutils_get_type(&current->is_signed,
@@ -514,7 +516,7 @@ int build_channel_array(const char *device_dir,
free(scan_el_dir);
/* reorder so that the array is in index order */
- bsort_channel_array_by_index(ci_array, *counter);
+ bsort_channel_array_by_index(*ci_array, *counter);
return 0;
@@ -524,6 +526,8 @@ error_cleanup_array:
free((*ci_array)[i].generic_name);
}
free(*ci_array);
+ *ci_array = NULL;
+ *counter = 0;
error_close_dir:
if (dp)
if (closedir(dp) == -1)
@@ -535,7 +539,7 @@ error_free_name:
return ret;
}
-int calc_digits(int num)
+static int calc_digits(int num)
{
int count = 0;
@@ -567,12 +571,12 @@ int find_type_by_name(const char *name, const char *type)
char *filename;
dp = opendir(iio_dir);
- if (dp == NULL) {
- printf("No industrialio devices available\n");
+ if (!dp) {
+ fprintf(stderr, "No industrialio devices available\n");
return -ENODEV;
}
- while (ent = readdir(dp), ent != NULL) {
+ while (ent = readdir(dp), ent) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0 &&
strlen(ent->d_name) > strlen(type) &&
@@ -581,11 +585,13 @@ int find_type_by_name(const char *name, const char *type)
ret = sscanf(ent->d_name + strlen(type), "%d", &number);
if (ret < 0) {
ret = -errno;
- printf("failed to read element number\n");
+ fprintf(stderr,
+ "failed to read element number\n");
goto error_close_dir;
} else if (ret != 1) {
ret = -EIO;
- printf("failed to match element number\n");
+ fprintf(stderr,
+ "failed to match element number\n");
goto error_close_dir;
}
@@ -595,7 +601,7 @@ int find_type_by_name(const char *name, const char *type)
":", 1) != 0) {
filename = malloc(strlen(iio_dir) + strlen(type)
+ numstrlen + 6);
- if (filename == NULL) {
+ if (!filename) {
ret = -ENOMEM;
goto error_close_dir;
}
@@ -654,7 +660,7 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
int test;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
- if (temp == NULL)
+ if (!temp)
return -ENOMEM;
ret = sprintf(temp, "%s/%s", basedir, filename);
@@ -662,9 +668,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
goto error_free;
sysfsfp = fopen(temp, "w");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
- printf("failed to open %s\n", temp);
+ fprintf(stderr, "failed to open %s\n", temp);
goto error_free;
}
@@ -683,9 +689,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
if (verify) {
sysfsfp = fopen(temp, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
- printf("failed to open %s\n", temp);
+ fprintf(stderr, "failed to open %s\n", temp);
goto error_free;
}
@@ -703,8 +709,9 @@ static int _write_sysfs_int(const char *filename, const char *basedir, int val,
}
if (test != val) {
- printf("Possible failure in int write %d to %s/%s\n",
- val, basedir, filename);
+ fprintf(stderr,
+ "Possible failure in int write %d to %s/%s\n",
+ val, basedir, filename);
ret = -1;
}
}
@@ -749,8 +756,8 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
- if (temp == NULL) {
- printf("Memory allocation failed\n");
+ if (!temp) {
+ fprintf(stderr, "Memory allocation failed\n");
return -ENOMEM;
}
@@ -759,9 +766,9 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
goto error_free;
sysfsfp = fopen(temp, "w");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
- printf("Could not open %s\n", temp);
+ fprintf(stderr, "Could not open %s\n", temp);
goto error_free;
}
@@ -780,9 +787,9 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
if (verify) {
sysfsfp = fopen(temp, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
- printf("Could not open file to verify\n");
+ fprintf(stderr, "Could not open file to verify\n");
goto error_free;
}
@@ -800,9 +807,10 @@ static int _write_sysfs_string(const char *filename, const char *basedir,
}
if (strcmp(temp, val) != 0) {
- printf("Possible failure in string write of %s "
- "Should be %s written to %s/%s\n", temp, val,
- basedir, filename);
+ fprintf(stderr,
+ "Possible failure in string write of %s "
+ "Should be %s written to %s/%s\n", temp, val,
+ basedir, filename);
ret = -1;
}
}
@@ -855,8 +863,8 @@ int read_sysfs_posint(const char *filename, const char *basedir)
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
- if (temp == NULL) {
- printf("Memory allocation failed");
+ if (!temp) {
+ fprintf(stderr, "Memory allocation failed");
return -ENOMEM;
}
@@ -865,7 +873,7 @@ int read_sysfs_posint(const char *filename, const char *basedir)
goto error_free;
sysfsfp = fopen(temp, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
goto error_free;
}
@@ -902,8 +910,8 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
- if (temp == NULL) {
- printf("Memory allocation failed");
+ if (!temp) {
+ fprintf(stderr, "Memory allocation failed");
return -ENOMEM;
}
@@ -912,7 +920,7 @@ int read_sysfs_float(const char *filename, const char *basedir, float *val)
goto error_free;
sysfsfp = fopen(temp, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
goto error_free;
}
@@ -949,8 +957,8 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
FILE *sysfsfp;
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
- if (temp == NULL) {
- printf("Memory allocation failed");
+ if (!temp) {
+ fprintf(stderr, "Memory allocation failed");
return -ENOMEM;
}
@@ -959,7 +967,7 @@ int read_sysfs_string(const char *filename, const char *basedir, char *str)
goto error_free;
sysfsfp = fopen(temp, "r");
- if (sysfsfp == NULL) {
+ if (!sysfsfp) {
ret = -errno;
goto error_free;
}
@@ -981,5 +989,3 @@ error_free:
return ret;
}
-
-#endif /* _IIO_UTILS_H */
diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h
index 086610139ade..e3503bfe538b 100644
--- a/tools/iio/iio_utils.h
+++ b/tools/iio/iio_utils.h
@@ -18,6 +18,8 @@
#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
#define FORMAT_TYPE_FILE "%s_type"
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
extern const char *iio_dir;
/**
@@ -58,7 +60,7 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
int iioutils_get_param_float(float *output, const char *param_name,
const char *device_dir, const char *name,
const char *generic_name);
-void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt);
+void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt);
int build_channel_array(const char *device_dir,
struct iio_channel_info **ci_array, int *counter);
int find_type_by_name(const char *name, const char *type);
diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c
index 7f432a55a6c4..3d650e668252 100644
--- a/tools/iio/lsiio.c
+++ b/tools/iio/lsiio.c
@@ -46,10 +46,10 @@ static int dump_channels(const char *dev_dir_name)
const struct dirent *ent;
dp = opendir(dev_dir_name);
- if (dp == NULL)
+ if (!dp)
return -errno;
- while (ent = readdir(dp), ent != NULL)
+ while (ent = readdir(dp), ent)
if (check_prefix(ent->d_name, "in_") &&
check_postfix(ent->d_name, "_raw"))
printf(" %-10s\n", ent->d_name);
@@ -69,7 +69,7 @@ static int dump_one_device(const char *dev_dir_name)
return -EINVAL;
ret = read_sysfs_string("name", dev_dir_name, name);
- if (ret)
+ if (ret < 0)
return ret;
printf("Device %03d: %s\n", dev_idx, name);
@@ -92,7 +92,7 @@ static int dump_one_trigger(const char *dev_dir_name)
return -EINVAL;
ret = read_sysfs_string("name", dev_dir_name, name);
- if (ret)
+ if (ret < 0)
return ret;
printf("Trigger %03d: %s\n", dev_idx, name);
@@ -107,12 +107,12 @@ static int dump_devices(void)
DIR *dp;
dp = opendir(iio_dir);
- if (dp == NULL) {
- printf("No industrial I/O devices available\n");
+ if (!dp) {
+ fprintf(stderr, "No industrial I/O devices available\n");
return -ENODEV;
}
- while (ent = readdir(dp), ent != NULL) {
+ while (ent = readdir(dp), ent) {
if (check_prefix(ent->d_name, type_device)) {
char *dev_dir_name;
@@ -134,7 +134,7 @@ static int dump_devices(void)
}
}
rewinddir(dp);
- while (ent = readdir(dp), ent != NULL) {
+ while (ent = readdir(dp), ent) {
if (check_prefix(ent->d_name, type_trigger)) {
char *dev_dir_name;